// This file is derived from the open-source Mono corlib.

//
// System.NumberFormatter.cs
//
// Author:
//   Kazuki Oikawa (kazuki@panicode.com)
//   Eyal Alaluf (eyala@mainsoft.com)
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
// Copyright (C) 2008 Mainsoft Co. (http://www.mainsoft.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System.Globalization;
using System.Text;
using System.Threading;

namespace System
{
	sealed class NumberFormatter
	{
		#region Static Fields

		const int32 DefaultExpPrecision = 6;
		const int32 HundredMillion = 100000000;
		const int64 SeventeenDigitsThreshold = 10000000000000000L;
		const uint64 ULongDivHundredMillion = UInt64.MaxValue / HundredMillion;
		const uint64 ULongModHundredMillion = 1 + UInt64.MaxValue % HundredMillion;

		const int32 DoubleBitsExponentShift = 52;
		const int32 DoubleBitsExponentMask = 0x7ff;
		const int64 DoubleBitsMantissaMask = 0x000FFFFF'FFFFFFFF;
		const int DecimalBitsScaleMask = 0x1f0000;

		const int32 SingleDefPrecision = 7;
		const int32 DoubleDefPrecision = 15;
		const int32 Int32DefPrecision = 10;
		const int32 UInt32DefPrecision = 10;
		const int32 Int64DefPrecision = 19;
		const int32 UInt64DefPrecision = 20;
		const int32 DecimalDefPrecision = 100;
		const int32 TenPowersListLength = 19;

		const double MinRoundtripVal = -1.79769313486231E+308;
		const double MaxRoundtripVal = 1.79769313486231E+308;

		// The below arrays are taken from mono/metatdata/number-formatter.h

		/*int a = 
		{
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
			1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
		};*/

		private const uint64[2048] MantissaBitsTable = .(
			4556951262222748432UL, 9113902524445496865UL, 1822780504889099373UL, 
			3645561009778198746UL, 7291122019556397492UL, 14582244039112794984UL, 
			2916448807822558996UL, 5832897615645117993UL, 11665795231290235987UL, 
			2333159046258047197UL, 4666318092516094394UL, 9332636185032188789UL, 
			1866527237006437757UL, 3733054474012875515UL, 7466108948025751031UL, 
			14932217896051502063UL, 2986443579210300412UL, 5972887158420600825UL, 
			11945774316841201651UL, 2389154863368240330UL, 4778309726736480660UL, 
			9556619453472961320UL, 1911323890694592264UL, 3822647781389184528UL, 
			7645295562778369056UL, 15290591125556738113UL, 3058118225111347622UL, 
			6116236450222695245UL, 12232472900445390490UL, 2446494580089078098UL, 
			4892989160178156196UL, 9785978320356312392UL, 1957195664071262478UL, 
			3914391328142524957UL, 7828782656285049914UL, 15657565312570099828UL, 
			3131513062514019965UL, 6263026125028039931UL, 12526052250056079862UL, 
			2505210450011215972UL, 5010420900022431944UL, 10020841800044863889UL, 
			2004168360008972777UL, 4008336720017945555UL, 8016673440035891111UL, 
			16033346880071782223UL, 3206669376014356444UL, 6413338752028712889UL, 
			12826677504057425779UL, 2565335500811485155UL, 5130671001622970311UL, 
			10261342003245940623UL, 2052268400649188124UL, 4104536801298376249UL, 
			8209073602596752498UL, 16418147205193504997UL, 3283629441038700999UL, 
			6567258882077401998UL, 13134517764154803997UL, 2626903552830960799UL, 
			5253807105661921599UL, 10507614211323843198UL, 2101522842264768639UL, 
			4203045684529537279UL, 8406091369059074558UL, 16812182738118149117UL, 
			3362436547623629823UL, 6724873095247259646UL, 13449746190494519293UL, 
			2689949238098903858UL, 5379898476197807717UL, 10759796952395615435UL, 
			2151959390479123087UL, 4303918780958246174UL, 8607837561916492348UL, 
			17215675123832984696UL, 3443135024766596939UL, 6886270049533193878UL, 
			13772540099066387756UL, 2754508019813277551UL, 5509016039626555102UL, 
			11018032079253110205UL, 2203606415850622041UL, 4407212831701244082UL, 
			8814425663402488164UL, 17628851326804976328UL, 3525770265360995265UL, 
			7051540530721990531UL, 14103081061443981063UL, 2820616212288796212UL, 
			5641232424577592425UL, 11282464849155184850UL, 2256492969831036970UL, 
			4512985939662073940UL, 9025971879324147880UL, 18051943758648295760UL, 
			3610388751729659152UL, 7220777503459318304UL, 14441555006918636608UL, 
			2888311001383727321UL, 5776622002767454643UL, 11553244005534909286UL, 
			2310648801106981857UL, 4621297602213963714UL, 9242595204427927429UL, 
			1848519040885585485UL, 3697038081771170971UL, 7394076163542341943UL, 
			14788152327084683887UL, 2957630465416936777UL, 5915260930833873554UL, 
			11830521861667747109UL, 2366104372333549421UL, 4732208744667098843UL, 
			9464417489334197687UL, 1892883497866839537UL, 3785766995733679075UL, 
			7571533991467358150UL, 15143067982934716300UL, 3028613596586943260UL, 
			6057227193173886520UL, 12114454386347773040UL, 2422890877269554608UL, 
			4845781754539109216UL, 9691563509078218432UL, 1938312701815643686UL, 
			3876625403631287372UL, 7753250807262574745UL, 15506501614525149491UL, 
			3101300322905029898UL, 6202600645810059796UL, 12405201291620119593UL, 
			2481040258324023918UL, 4962080516648047837UL, 9924161033296095674UL, 
			1984832206659219134UL, 3969664413318438269UL, 7939328826636876539UL, 
			15878657653273753079UL, 3175731530654750615UL, 6351463061309501231UL, 
			12702926122619002463UL, 2540585224523800492UL, 5081170449047600985UL, 
			10162340898095201970UL, 2032468179619040394UL, 4064936359238080788UL, 
			8129872718476161576UL, 16259745436952323153UL, 3251949087390464630UL, 
			6503898174780929261UL, 13007796349561858522UL, 2601559269912371704UL, 
			5203118539824743409UL, 10406237079649486818UL, 2081247415929897363UL, 
			4162494831859794727UL, 8324989663719589454UL, 16649979327439178909UL, 
			3329995865487835781UL, 6659991730975671563UL, 13319983461951343127UL, 
			2663996692390268625UL, 5327993384780537250UL, 10655986769561074501UL, 
			2131197353912214900UL, 4262394707824429800UL, 8524789415648859601UL, 
			17049578831297719202UL, 3409915766259543840UL, 6819831532519087681UL, 
			13639663065038175362UL, 2727932613007635072UL, 5455865226015270144UL, 
			10911730452030540289UL, 2182346090406108057UL, 4364692180812216115UL, 
			8729384361624432231UL, 17458768723248864463UL, 3491753744649772892UL, 
			6983507489299545785UL, 13967014978599091570UL, 2793402995719818314UL, 
			5586805991439636628UL, 11173611982879273256UL, 2234722396575854651UL, 
			4469444793151709302UL, 8938889586303418605UL, 17877779172606837210UL, 
			3575555834521367442UL, 7151111669042734884UL, 14302223338085469768UL, 
			2860444667617093953UL, 5720889335234187907UL, 11441778670468375814UL, 
			2288355734093675162UL, 4576711468187350325UL, 9153422936374700651UL, 
			1830684587274940130UL, 3661369174549880260UL, 7322738349099760521UL, 
			14645476698199521043UL, 2929095339639904208UL, 5858190679279808417UL, 
			11716381358559616834UL, 2343276271711923366UL, 4686552543423846733UL, 
			9373105086847693467UL, 1874621017369538693UL, 3749242034739077387UL, 
			7498484069478154774UL, 14996968138956309548UL, 2999393627791261909UL, 
			5998787255582523819UL, 11997574511165047638UL, 2399514902233009527UL, 
			4799029804466019055UL, 9598059608932038110UL, 1919611921786407622UL, 
			3839223843572815244UL, 7678447687145630488UL, 15356895374291260977UL, 
			3071379074858252195UL, 6142758149716504390UL, 12285516299433008781UL, 
			2457103259886601756UL, 4914206519773203512UL, 9828413039546407025UL, 
			1965682607909281405UL, 3931365215818562810UL, 7862730431637125620UL, 
			15725460863274251240UL, 3145092172654850248UL, 6290184345309700496UL, 
			12580368690619400992UL, 2516073738123880198UL, 5032147476247760397UL, 
			10064294952495520794UL, 2012858990499104158UL, 4025717980998208317UL, 
			8051435961996416635UL, 16102871923992833270UL, 3220574384798566654UL, 
			6441148769597133308UL, 12882297539194266616UL, 2576459507838853323UL, 
			5152919015677706646UL, 10305838031355413293UL, 2061167606271082658UL, 
			4122335212542165317UL, 8244670425084330634UL, 16489340850168661269UL, 
			3297868170033732253UL, 6595736340067464507UL, 13191472680134929015UL, 
			2638294536026985803UL, 5276589072053971606UL, 10553178144107943212UL, 
			2110635628821588642UL, 4221271257643177284UL, 8442542515286354569UL, 
			16885085030572709139UL, 3377017006114541827UL, 6754034012229083655UL, 
			13508068024458167311UL, 2701613604891633462UL, 5403227209783266924UL, 
			10806454419566533849UL, 2161290883913306769UL, 4322581767826613539UL, 
			8645163535653227079UL, 17290327071306454158UL, 3458065414261290831UL, 
			6916130828522581663UL, 13832261657045163327UL, 2766452331409032665UL, 
			5532904662818065330UL, 11065809325636130661UL, 2213161865127226132UL, 
			4426323730254452264UL, 8852647460508904529UL, 17705294921017809058UL, 
			3541058984203561811UL, 7082117968407123623UL, 14164235936814247246UL, 
			2832847187362849449UL, 5665694374725698898UL, 11331388749451397797UL, 
			2266277749890279559UL, 4532555499780559119UL, 9065110999561118238UL, 
			1813022199912223647UL, 3626044399824447295UL, 7252088799648894590UL, 
			14504177599297789180UL, 2900835519859557836UL, 5801671039719115672UL, 
			11603342079438231344UL, 2320668415887646268UL, 4641336831775292537UL, 
			9282673663550585075UL, 1856534732710117015UL, 3713069465420234030UL, 
			7426138930840468060UL, 14852277861680936121UL, 2970455572336187224UL, 
			5940911144672374448UL, 11881822289344748896UL, 2376364457868949779UL, 
			4752728915737899558UL, 9505457831475799117UL, 1901091566295159823UL, 
			3802183132590319647UL, 7604366265180639294UL, 15208732530361278588UL, 
			3041746506072255717UL, 6083493012144511435UL, 12166986024289022870UL, 
			2433397204857804574UL, 4866794409715609148UL, 9733588819431218296UL, 
			1946717763886243659UL, 3893435527772487318UL, 7786871055544974637UL, 
			15573742111089949274UL, 3114748422217989854UL, 6229496844435979709UL, 
			12458993688871959419UL, 2491798737774391883UL, 4983597475548783767UL, 
			9967194951097567535UL, 1993438990219513507UL, 3986877980439027014UL, 
			7973755960878054028UL, 15947511921756108056UL, 3189502384351221611UL, 
			6379004768702443222UL, 12758009537404886445UL, 2551601907480977289UL, 
			5103203814961954578UL, 10206407629923909156UL, 2041281525984781831UL, 
			4082563051969563662UL, 8165126103939127325UL, 16330252207878254650UL, 
			3266050441575650930UL, 6532100883151301860UL, 13064201766302603720UL, 
			2612840353260520744UL, 5225680706521041488UL, 10451361413042082976UL, 
			2090272282608416595UL, 4180544565216833190UL, 8361089130433666380UL, 
			16722178260867332761UL, 3344435652173466552UL, 6688871304346933104UL, 
			13377742608693866209UL, 2675548521738773241UL, 5351097043477546483UL, 
			10702194086955092967UL, 2140438817391018593UL, 4280877634782037187UL, 
			8561755269564074374UL, 17123510539128148748UL, 3424702107825629749UL, 
			6849404215651259499UL, 13698808431302518998UL, 2739761686260503799UL, 
			5479523372521007599UL, 10959046745042015198UL, 2191809349008403039UL, 
			4383618698016806079UL, 8767237396033612159UL, 17534474792067224318UL, 
			3506894958413444863UL, 7013789916826889727UL, 14027579833653779454UL, 
			2805515966730755890UL, 5611031933461511781UL, 11222063866923023563UL, 
			2244412773384604712UL, 4488825546769209425UL, 8977651093538418850UL, 
			17955302187076837701UL, 3591060437415367540UL, 7182120874830735080UL, 
			14364241749661470161UL, 2872848349932294032UL, 5745696699864588064UL, 
			11491393399729176129UL, 2298278679945835225UL, 4596557359891670451UL, 
			9193114719783340903UL, 1838622943956668180UL, 3677245887913336361UL, 
			7354491775826672722UL, 14708983551653345445UL, 2941796710330669089UL, 
			5883593420661338178UL, 11767186841322676356UL, 2353437368264535271UL, 
			4706874736529070542UL, 9413749473058141084UL, 1882749894611628216UL, 
			3765499789223256433UL, 7530999578446512867UL, 15061999156893025735UL, 
			3012399831378605147UL, 6024799662757210294UL, 12049599325514420588UL, 
			2409919865102884117UL, 4819839730205768235UL, 9639679460411536470UL, 
			1927935892082307294UL, 3855871784164614588UL, 7711743568329229176UL, 
			15423487136658458353UL, 3084697427331691670UL, 6169394854663383341UL, 
			12338789709326766682UL, 2467757941865353336UL, 4935515883730706673UL, 
			9871031767461413346UL, 1974206353492282669UL, 3948412706984565338UL, 
			7896825413969130677UL, 15793650827938261354UL, 3158730165587652270UL, 
			6317460331175304541UL, 12634920662350609083UL, 2526984132470121816UL, 
			5053968264940243633UL, 10107936529880487266UL, 2021587305976097453UL, 
			4043174611952194906UL, 8086349223904389813UL, 16172698447808779626UL, 
			3234539689561755925UL, 6469079379123511850UL, 12938158758247023701UL, 
			2587631751649404740UL, 5175263503298809480UL, 10350527006597618960UL, 
			2070105401319523792UL, 4140210802639047584UL, 8280421605278095168UL, 
			16560843210556190337UL, 3312168642111238067UL, 6624337284222476135UL, 
			13248674568444952270UL, 2649734913688990454UL, 5299469827377980908UL, 
			10598939654755961816UL, 2119787930951192363UL, 4239575861902384726UL, 
			8479151723804769452UL, 16958303447609538905UL, 3391660689521907781UL, 
			6783321379043815562UL, 13566642758087631124UL, 2713328551617526224UL, 
			5426657103235052449UL, 10853314206470104899UL, 2170662841294020979UL, 
			4341325682588041959UL, 8682651365176083919UL, 17365302730352167839UL, 
			3473060546070433567UL, 6946121092140867135UL, 13892242184281734271UL, 
			2778448436856346854UL, 5556896873712693708UL, 11113793747425387417UL, 
			2222758749485077483UL, 4445517498970154966UL, 8891034997940309933UL, 
			17782069995880619867UL, 3556413999176123973UL, 7112827998352247947UL, 
			14225655996704495894UL, 2845131199340899178UL, 5690262398681798357UL, 
			11380524797363596715UL, 2276104959472719343UL, 4552209918945438686UL, 
			9104419837890877372UL, 1820883967578175474UL, 3641767935156350948UL, 
			7283535870312701897UL, 14567071740625403795UL, 2913414348125080759UL, 
			5826828696250161518UL, 11653657392500323036UL, 2330731478500064607UL, 
			4661462957000129214UL, 9322925914000258429UL, 1864585182800051685UL, 
			3729170365600103371UL, 7458340731200206743UL, 14916681462400413486UL, 
			2983336292480082697UL, 5966672584960165394UL, 11933345169920330789UL, 
			2386669033984066157UL, 4773338067968132315UL, 9546676135936264631UL, 
			1909335227187252926UL, 3818670454374505852UL, 7637340908749011705UL, 
			15274681817498023410UL, 3054936363499604682UL, 6109872726999209364UL, 
			12219745453998418728UL, 2443949090799683745UL, 4887898181599367491UL, 
			9775796363198734982UL, 1955159272639746996UL, 3910318545279493993UL, 
			7820637090558987986UL, 15641274181117975972UL, 3128254836223595194UL, 
			6256509672447190388UL, 12513019344894380777UL, 2502603868978876155UL, 
			5005207737957752311UL, 10010415475915504622UL, 2002083095183100924UL, 
			4004166190366201848UL, 8008332380732403697UL, 16016664761464807395UL, 
			3203332952292961479UL, 6406665904585922958UL, 12813331809171845916UL, 
			2562666361834369183UL, 5125332723668738366UL, 10250665447337476733UL, 
			2050133089467495346UL, 4100266178934990693UL, 8200532357869981386UL, 
			16401064715739962772UL, 3280212943147992554UL, 6560425886295985109UL, 
			13120851772591970218UL, 2624170354518394043UL, 5248340709036788087UL, 
			10496681418073576174UL, 2099336283614715234UL, 4198672567229430469UL, 
			8397345134458860939UL, 16794690268917721879UL, 3358938053783544375UL, 
			6717876107567088751UL, 13435752215134177503UL, 2687150443026835500UL, 
			5374300886053671001UL, 10748601772107342002UL, 2149720354421468400UL, 
			4299440708842936801UL, 8598881417685873602UL, 17197762835371747204UL, 
			3439552567074349440UL, 6879105134148698881UL, 13758210268297397763UL, 
			2751642053659479552UL, 5503284107318959105UL, 11006568214637918210UL, 
			2201313642927583642UL, 4402627285855167284UL, 8805254571710334568UL, 
			17610509143420669137UL, 3522101828684133827UL, 7044203657368267654UL, 
			14088407314736535309UL, 2817681462947307061UL, 5635362925894614123UL, 
			11270725851789228247UL, 2254145170357845649UL, 4508290340715691299UL, 
			9016580681431382598UL, 18033161362862765196UL, 3606632272572553039UL, 
			7213264545145106078UL, 14426529090290212157UL, 2885305818058042431UL, 
			5770611636116084862UL, 11541223272232169725UL, 2308244654446433945UL, 
			4616489308892867890UL, 9232978617785735780UL, 1846595723557147156UL, 
			3693191447114294312UL, 7386382894228588624UL, 14772765788457177249UL, 
			2954553157691435449UL, 5909106315382870899UL, 11818212630765741799UL, 
			2363642526153148359UL, 4727285052306296719UL, 9454570104612593439UL, 
			1890914020922518687UL, 3781828041845037375UL, 7563656083690074751UL, 
			15127312167380149503UL, 3025462433476029900UL, 6050924866952059801UL, 
			12101849733904119602UL, 2420369946780823920UL, 4840739893561647841UL, 
			9681479787123295682UL, 1936295957424659136UL, 3872591914849318272UL, 
			7745183829698636545UL, 15490367659397273091UL, 3098073531879454618UL, 
			6196147063758909236UL, 12392294127517818473UL, 2478458825503563694UL, 
			4956917651007127389UL, 9913835302014254778UL, 1982767060402850955UL, 
			3965534120805701911UL, 7931068241611403822UL, 15862136483222807645UL, 
			3172427296644561529UL, 6344854593289123058UL, 12689709186578246116UL, 
			2537941837315649223UL, 5075883674631298446UL, 10151767349262596893UL, 
			2030353469852519378UL, 4060706939705038757UL, 8121413879410077514UL, 
			16242827758820155028UL, 3248565551764031005UL, 6497131103528062011UL, 
			12994262207056124023UL, 2598852441411224804UL, 5197704882822449609UL, 
			10395409765644899218UL, 2079081953128979843UL, 4158163906257959687UL, 
			8316327812515919374UL, 16632655625031838749UL, 3326531125006367749UL, 
			6653062250012735499UL, 13306124500025470999UL, 2661224900005094199UL, 
			5322449800010188399UL, 10644899600020376799UL, 2128979920004075359UL, 
			4257959840008150719UL, 8515919680016301439UL, 17031839360032602879UL, 
			3406367872006520575UL, 6812735744013041151UL, 13625471488026082303UL, 
			2725094297605216460UL, 5450188595210432921UL, 10900377190420865842UL, 
			2180075438084173168UL, 4360150876168346337UL, 8720301752336692674UL, 
			17440603504673385348UL, 3488120700934677069UL, 6976241401869354139UL, 
			13952482803738708279UL, 2790496560747741655UL, 5580993121495483311UL, 
			11161986242990966623UL, 2232397248598193324UL, 4464794497196386649UL, 
			8929588994392773298UL, 17859177988785546597UL, 3571835597757109319UL, 
			7143671195514218638UL, 14287342391028437277UL, 2857468478205687455UL, 
			5714936956411374911UL, 11429873912822749822UL, 2285974782564549964UL, 
			4571949565129099928UL, 9143899130258199857UL, 1828779826051639971UL, 
			3657559652103279943UL, 7315119304206559886UL, 14630238608413119772UL, 
			2926047721682623954UL, 5852095443365247908UL, 11704190886730495817UL, 
			2340838177346099163UL, 4681676354692198327UL, 9363352709384396654UL, 
			1872670541876879330UL, 3745341083753758661UL, 7490682167507517323UL, 
			14981364335015034646UL, 2996272867003006929UL, 5992545734006013858UL, 
			11985091468012027717UL, 2397018293602405543UL, 4794036587204811087UL, 
			9588073174409622174UL, 1917614634881924434UL, 3835229269763848869UL, 
			7670458539527697739UL, 15340917079055395478UL, 3068183415811079095UL, 
			6136366831622158191UL, 12272733663244316382UL, 2454546732648863276UL, 
			4909093465297726553UL, 9818186930595453106UL, 1963637386119090621UL, 
			3927274772238181242UL, 7854549544476362484UL, 15709099088952724969UL, 
			3141819817790544993UL, 6283639635581089987UL, 12567279271162179975UL, 
			2513455854232435995UL, 5026911708464871990UL, 10053823416929743980UL, 
			2010764683385948796UL, 4021529366771897592UL, 8043058733543795184UL, 
			16086117467087590369UL, 3217223493417518073UL, 6434446986835036147UL, 
			12868893973670072295UL, 2573778794734014459UL, 5147557589468028918UL, 
			10295115178936057836UL, 2059023035787211567UL, 4118046071574423134UL, 
			8236092143148846269UL, 16472184286297692538UL, 3294436857259538507UL, 
			6588873714519077015UL, 13177747429038154030UL, 2635549485807630806UL, 
			5271098971615261612UL, 10542197943230523224UL, 2108439588646104644UL, 
			4216879177292209289UL, 8433758354584418579UL, 16867516709168837158UL, 
			3373503341833767431UL, 6747006683667534863UL, 13494013367335069727UL, 
			2698802673467013945UL, 5397605346934027890UL, 10795210693868055781UL, 
			2159042138773611156UL, 4318084277547222312UL, 8636168555094444625UL, 
			17272337110188889250UL, 3454467422037777850UL, 6908934844075555700UL, 
			13817869688151111400UL, 2763573937630222280UL, 5527147875260444560UL, 
			11054295750520889120UL, 2210859150104177824UL, 4421718300208355648UL, 
			8843436600416711296UL, 17686873200833422592UL, 3537374640166684518UL, 
			7074749280333369037UL, 14149498560666738074UL, 2829899712133347614UL, 
			5659799424266695229UL, 11319598848533390459UL, 2263919769706678091UL, 
			4527839539413356183UL, 9055679078826712367UL, 1811135815765342473UL, 
			3622271631530684947UL, 7244543263061369894UL, 14489086526122739788UL, 
			2897817305224547957UL, 5795634610449095915UL, 11591269220898191830UL, 
			2318253844179638366UL, 4636507688359276732UL, 9273015376718553464UL, 
			1854603075343710692UL, 3709206150687421385UL, 7418412301374842771UL, 
			14836824602749685542UL, 2967364920549937108UL, 5934729841099874217UL, 
			11869459682199748434UL, 2373891936439949686UL, 4747783872879899373UL, 
			9495567745759798747UL, 1899113549151959749UL, 3798227098303919498UL, 
			7596454196607838997UL, 15192908393215677995UL, 3038581678643135599UL, 
			6077163357286271198UL, 12154326714572542396UL, 2430865342914508479UL, 
			4861730685829016958UL, 9723461371658033917UL, 1944692274331606783UL, 
			3889384548663213566UL, 7778769097326427133UL, 15557538194652854267UL, 
			3111507638930570853UL, 6223015277861141707UL, 12446030555722283414UL, 
			2489206111144456682UL, 4978412222288913365UL, 9956824444577826731UL, 
			1991364888915565346UL, 3982729777831130692UL, 7965459555662261385UL, 
			15930919111324522770UL, 3186183822264904554UL, 6372367644529809108UL, 
			12744735289059618216UL, 2548947057811923643UL, 5097894115623847286UL, 
			10195788231247694572UL, 2039157646249538914UL, 4078315292499077829UL, 
			8156630584998155658UL, 16313261169996311316UL, 3262652233999262263UL, 
			6525304467998524526UL, 13050608935997049053UL, 2610121787199409810UL, 
			5220243574398819621UL, 10440487148797639242UL, 2088097429759527848UL, 
			4176194859519055697UL, 8352389719038111394UL, 16704779438076222788UL, 
			3340955887615244557UL, 6681911775230489115UL, 13363823550460978230UL, 
			2672764710092195646UL, 5345529420184391292UL, 10691058840368782584UL, 
			2138211768073756516UL, 4276423536147513033UL, 8552847072295026067UL, 
			17105694144590052135UL, 3421138828918010427UL, 6842277657836020854UL, 
			13684555315672041708UL, 2736911063134408341UL, 5473822126268816683UL, 
			10947644252537633366UL, 2189528850507526673UL, 4379057701015053346UL, 
			8758115402030106693UL, 17516230804060213386UL, 3503246160812042677UL, 
			7006492321624085354UL, 14012984643248170709UL, 2802596928649634141UL, 
			5605193857299268283UL, 11210387714598536567UL, 2242077542919707313UL, 
			4484155085839414626UL, 8968310171678829253UL, 17936620343357658507UL, 
			3587324068671531701UL, 7174648137343063403UL, 14349296274686126806UL, 
			2869859254937225361UL, 5739718509874450722UL, 11479437019748901445UL, 
			2295887403949780289UL, 4591774807899560578UL, 9183549615799121156UL, 
			1836709923159824231UL, 3673419846319648462UL, 7346839692639296924UL, 
			14693679385278593849UL, 2938735877055718769UL, 5877471754111437539UL, 
			11754943508222875079UL, 2350988701644575015UL, 4701977403289150031UL, 
			9403954806578300063UL, 1880790961315660012UL, 3761581922631320025UL, 
			7523163845262640050UL, 15046327690525280101UL, 3009265538105056020UL, 
			6018531076210112040UL, 12037062152420224081UL, 2407412430484044816UL, 
			4814824860968089632UL, 9629649721936179265UL, 1925929944387235853UL, 
			3851859888774471706UL, 7703719777548943412UL, 15407439555097886824UL, 
			3081487911019577364UL, 6162975822039154729UL, 12325951644078309459UL, 
			2465190328815661891UL, 4930380657631323783UL, 9860761315262647567UL, 
			1972152263052529513UL, 3944304526105059027UL, 7888609052210118054UL, 
			15777218104420236108UL, 3155443620884047221UL, 6310887241768094443UL, 
			12621774483536188886UL, 2524354896707237777UL, 5048709793414475554UL, 
			10097419586828951109UL, 2019483917365790221UL, 4038967834731580443UL, 
			8077935669463160887UL, 16155871338926321774UL, 3231174267785264354UL, 
			6462348535570528709UL, 12924697071141057419UL, 2584939414228211483UL, 
			5169878828456422967UL, 10339757656912845935UL, 2067951531382569187UL, 
			4135903062765138374UL, 8271806125530276748UL, 16543612251060553497UL, 
			3308722450212110699UL, 6617444900424221398UL, 13234889800848442797UL, 
			2646977960169688559UL, 5293955920339377119UL, 10587911840678754238UL, 
			2117582368135750847UL, 4235164736271501695UL, 8470329472543003390UL, 
			16940658945086006781UL, 3388131789017201356UL, 6776263578034402712UL, 
			13552527156068805425UL, 2710505431213761085UL, 5421010862427522170UL, 
			10842021724855044340UL, 2168404344971008868UL, 4336808689942017736UL, 
			8673617379884035472UL, 17347234759768070944UL, 3469446951953614188UL, 
			6938893903907228377UL, 13877787807814456755UL, 2775557561562891351UL, 
			5551115123125782702UL, 11102230246251565404UL, 2220446049250313080UL, 
			4440892098500626161UL, 8881784197001252323UL, 17763568394002504646UL, 
			3552713678800500929UL, 7105427357601001858UL, 14210854715202003717UL, 
			2842170943040400743UL, 5684341886080801486UL, 11368683772161602973UL, 
			2273736754432320594UL, 4547473508864641189UL, 9094947017729282379UL, 
			1818989403545856475UL, 3637978807091712951UL, 7275957614183425903UL, 
			14551915228366851806UL, 2910383045673370361UL, 5820766091346740722UL, 
			11641532182693481445UL, 2328306436538696289UL, 4656612873077392578UL, 
			9313225746154785156UL, 1862645149230957031UL, 3725290298461914062UL, 
			7450580596923828125UL, 14901161193847656250UL, 2980232238769531250UL, 
			5960464477539062500UL, 11920928955078125000UL, 2384185791015625000UL, 
			4768371582031250000UL, 9536743164062500000UL, 1907348632812500000UL, 
			3814697265625000000UL, 7629394531250000000UL, 15258789062500000000UL, 
			3051757812500000000UL, 6103515625000000000UL, 12207031250000000000UL, 
			2441406250000000000UL, 4882812500000000000UL, 9765625000000000000UL, 
			1953125000000000000UL, 3906250000000000000UL, 7812500000000000000UL, 
			15625000000000000000UL, 3125000000000000000UL, 6250000000000000000UL, 
			12500000000000000000UL, 2500000000000000000UL, 5000000000000000000UL, 
			10000000000000000000UL, 2000000000000000000UL, 4000000000000000000UL, 
			8000000000000000000UL, 16000000000000000000UL, 3200000000000000000UL, 
			6400000000000000000UL, 12800000000000000000UL, 2560000000000000000UL, 
			5120000000000000000UL, 10240000000000000000UL, 2048000000000000000UL, 
			4096000000000000000UL, 8192000000000000000UL, 16384000000000000000UL, 
			3276800000000000000UL, 6553600000000000000UL, 13107200000000000000UL, 
			2621440000000000000UL, 5242880000000000000UL, 10485760000000000000UL, 
			2097152000000000000UL, 4194304000000000000UL, 8388608000000000000UL, 
			16777216000000000000UL, 3355443200000000000UL, 6710886400000000000UL, 
			13421772800000000000UL, 2684354560000000000UL, 5368709120000000000UL, 
			10737418240000000000UL, 2147483648000000000UL, 4294967296000000000UL, 
			8589934592000000000UL, 17179869184000000000UL, 3435973836800000000UL, 
			6871947673600000000UL, 13743895347200000000UL, 2748779069440000000UL, 
			5497558138880000000UL, 10995116277760000000UL, 2199023255552000000UL, 
			4398046511104000000UL, 8796093022208000000UL, 17592186044416000000UL, 
			3518437208883200000UL, 7036874417766400000UL, 14073748835532800000UL, 
			2814749767106560000UL, 5629499534213120000UL, 11258999068426240000UL, 
			2251799813685248000UL, 4503599627370496000UL, 9007199254740992000UL, 
			18014398509481984000UL, 3602879701896396800UL, 7205759403792793600UL, 
			14411518807585587200UL, 2882303761517117440UL, 5764607523034234880UL, 
			11529215046068469760UL, 2305843009213693952UL, 4611686018427387904UL, 
			9223372036854775808UL, 1844674407370955161UL, 3689348814741910323UL, 
			7378697629483820646UL, 14757395258967641292UL, 2951479051793528258UL, 
			5902958103587056517UL, 11805916207174113034UL, 2361183241434822606UL, 
			4722366482869645213UL, 9444732965739290427UL, 1888946593147858085UL, 
			3777893186295716170UL, 7555786372591432341UL, 15111572745182864683UL, 
			3022314549036572936UL, 6044629098073145873UL, 12089258196146291747UL, 
			2417851639229258349UL, 4835703278458516698UL, 9671406556917033397UL, 
			1934281311383406679UL, 3868562622766813359UL, 7737125245533626718UL, 
			15474250491067253436UL, 3094850098213450687UL, 6189700196426901374UL, 
			12379400392853802748UL, 2475880078570760549UL, 4951760157141521099UL, 
			9903520314283042199UL, 1980704062856608439UL, 3961408125713216879UL, 
			7922816251426433759UL, 15845632502852867518UL, 3169126500570573503UL, 
			6338253001141147007UL, 12676506002282294014UL, 2535301200456458802UL, 
			5070602400912917605UL, 10141204801825835211UL, 2028240960365167042UL, 
			4056481920730334084UL, 8112963841460668169UL, 16225927682921336339UL, 
			3245185536584267267UL, 6490371073168534535UL, 12980742146337069071UL, 
			2596148429267413814UL, 5192296858534827628UL, 10384593717069655257UL, 
			2076918743413931051UL, 4153837486827862102UL, 8307674973655724205UL, 
			16615349947311448411UL, 3323069989462289682UL, 6646139978924579364UL, 
			13292279957849158729UL, 2658455991569831745UL, 5316911983139663491UL, 
			10633823966279326983UL, 2126764793255865396UL, 4253529586511730793UL, 
			8507059173023461586UL, 17014118346046923173UL, 3402823669209384634UL, 
			6805647338418769269UL, 13611294676837538538UL, 2722258935367507707UL, 
			5444517870735015415UL, 10889035741470030830UL, 2177807148294006166UL, 
			4355614296588012332UL, 8711228593176024664UL, 17422457186352049329UL, 
			3484491437270409865UL, 6968982874540819731UL, 13937965749081639463UL, 
			2787593149816327892UL, 5575186299632655785UL, 11150372599265311570UL, 
			2230074519853062314UL, 4460149039706124628UL, 8920298079412249256UL, 
			17840596158824498513UL, 3568119231764899702UL, 7136238463529799405UL, 
			14272476927059598810UL, 2854495385411919762UL, 5708990770823839524UL, 
			11417981541647679048UL, 2283596308329535809UL, 4567192616659071619UL, 
			9134385233318143238UL, 1826877046663628647UL, 3653754093327257295UL, 
			7307508186654514591UL, 14615016373309029182UL, 2923003274661805836UL, 
			5846006549323611672UL, 11692013098647223345UL, 2338402619729444669UL, 
			4676805239458889338UL, 9353610478917778676UL, 1870722095783555735UL, 
			3741444191567111470UL, 7482888383134222941UL, 14965776766268445882UL, 
			2993155353253689176UL, 5986310706507378352UL, 11972621413014756705UL, 
			2394524282602951341UL, 4789048565205902682UL, 9578097130411805364UL, 
			1915619426082361072UL, 3831238852164722145UL, 7662477704329444291UL, 
			15324955408658888583UL, 3064991081731777716UL, 6129982163463555433UL, 
			12259964326927110866UL, 2451992865385422173UL, 4903985730770844346UL, 
			9807971461541688693UL, 1961594292308337738UL, 3923188584616675477UL, 
			7846377169233350954UL, 15692754338466701909UL, 3138550867693340381UL, 
			6277101735386680763UL, 12554203470773361527UL, 2510840694154672305UL, 
			5021681388309344611UL, 10043362776618689222UL, 2008672555323737844UL, 
			4017345110647475688UL, 8034690221294951377UL, 16069380442589902755UL, 
			3213876088517980551UL, 6427752177035961102UL, 12855504354071922204UL, 
			2571100870814384440UL, 5142201741628768881UL, 10284403483257537763UL, 
			2056880696651507552UL, 4113761393303015105UL, 8227522786606030210UL, 
			16455045573212060421UL, 3291009114642412084UL, 6582018229284824168UL, 
			13164036458569648337UL, 2632807291713929667UL, 5265614583427859334UL, 
			10531229166855718669UL, 2106245833371143733UL, 4212491666742287467UL, 
			8424983333484574935UL, 16849966666969149871UL, 3369993333393829974UL, 
			6739986666787659948UL, 13479973333575319897UL, 2695994666715063979UL, 
			5391989333430127958UL, 10783978666860255917UL, 2156795733372051183UL, 
			4313591466744102367UL, 8627182933488204734UL, 17254365866976409468UL, 
			3450873173395281893UL, 6901746346790563787UL, 13803492693581127574UL, 
			2760698538716225514UL, 5521397077432451029UL, 11042794154864902059UL, 
			2208558830972980411UL, 4417117661945960823UL, 8834235323891921647UL, 
			17668470647783843295UL, 3533694129556768659UL, 7067388259113537318UL, 
			14134776518227074636UL, 2826955303645414927UL, 5653910607290829854UL, 
			11307821214581659709UL, 2261564242916331941UL, 4523128485832663883UL, 
			9046256971665327767UL, 18092513943330655534UL, 3618502788666131106UL, 
			7237005577332262213UL, 14474011154664524427UL, 2894802230932904885UL, 
			5789604461865809771UL, 11579208923731619542UL, 2315841784746323908UL, 
			4631683569492647816UL, 9263367138985295633UL, 1852673427797059126UL, 
			3705346855594118253UL, 7410693711188236507UL, 14821387422376473014UL, 
			2964277484475294602UL, 5928554968950589205UL, 11857109937901178411UL, 
			2371421987580235682UL, 4742843975160471364UL, 9485687950320942729UL, 
			1897137590064188545UL, 3794275180128377091UL, 7588550360256754183UL, 
			15177100720513508366UL, 3035420144102701673UL, 6070840288205403346UL, 
			12141680576410806693UL, 2428336115282161338UL, 4856672230564322677UL, 
			9713344461128645354UL, 1942668892225729070UL, 3885337784451458141UL, 
			7770675568902916283UL, 15541351137805832567UL, 3108270227561166513UL, 
			6216540455122333026UL, 12433080910244666053UL, 2486616182048933210UL, 
			4973232364097866421UL, 9946464728195732843UL, 1989292945639146568UL, 
			3978585891278293137UL, 7957171782556586274UL, 15914343565113172548UL, 
			3182868713022634509UL, 6365737426045269019UL, 12731474852090538039UL, 
			2546294970418107607UL, 5092589940836215215UL, 10185179881672430431UL, 
			2037035976334486086UL, 4074071952668972172UL, 8148143905337944345UL, 
			16296287810675888690UL, 3259257562135177738UL, 6518515124270355476UL, 
			13037030248540710952UL, 2607406049708142190UL, 5214812099416284380UL, 
			10429624198832568761UL, 2085924839766513752UL, 4171849679533027504UL, 
			8343699359066055009UL, 16687398718132110018UL, 3337479743626422003UL, 
			6674959487252844007UL, 13349918974505688014UL, 2669983794901137602UL, 
			5339967589802275205UL, 10679935179604550411UL, 2135987035920910082UL, 
			4271974071841820164UL, 8543948143683640329UL, 17087896287367280659UL, 
			3417579257473456131UL, 6835158514946912263UL, 13670317029893824527UL, 
			2734063405978764905UL, 5468126811957529810UL, 10936253623915059621UL, 
			2187250724783011924UL, 4374501449566023848UL, 8749002899132047697UL, 
			17498005798264095394UL, 3499601159652819078UL, 6999202319305638157UL, 
			13998404638611276315UL, 2799680927722255263UL, 5599361855444510526UL, 
			11198723710889021052UL, 2239744742177804210UL, 4479489484355608421UL, 
			8958978968711216842UL, 17917957937422433684UL, 3583591587484486736UL, 
			7167183174968973473UL, 14334366349937946947UL, 2866873269987589389UL, 
			5733746539975178779UL, 11467493079950357558UL, 2293498615990071511UL, 
			4586997231980143023UL, 9173994463960286046UL, 1834798892792057209UL, 
			3669597785584114418UL, 7339195571168228837UL, 14678391142336457674UL, 
			2935678228467291534UL, 5871356456934583069UL, 11742712913869166139UL, 
			2348542582773833227UL, 4697085165547666455UL, 9394170331095332911UL, 
			1878834066219066582UL, 3757668132438133164UL, 7515336264876266329UL, 
			15030672529752532658UL, 3006134505950506531UL, 6012269011901013063UL, 
			12024538023802026126UL, 2404907604760405225UL, 4809815209520810450UL, 
			9619630419041620901UL, 1923926083808324180UL, 3847852167616648360UL, 
			7695704335233296721UL, 15391408670466593442UL, 3078281734093318688UL, 
			6156563468186637376UL, 12313126936373274753UL, 2462625387274654950UL, 
			4925250774549309901UL, 9850501549098619803UL, 1970100309819723960UL, 
			3940200619639447921UL, 7880401239278895842UL, 15760802478557791684UL, 
			3152160495711558336UL, 6304320991423116673UL, 12608641982846233347UL, 
			2521728396569246669UL, 5043456793138493339UL, 10086913586276986678UL, 
			2017382717255397335UL, 4034765434510794671UL, 8069530869021589342UL, 
			16139061738043178685UL, 3227812347608635737UL, 6455624695217271474UL, 
			12911249390434542948UL, 2582249878086908589UL, 5164499756173817179UL, 
			10328999512347634358UL, 2065799902469526871UL, 4131599804939053743UL, 
			8263199609878107486UL, 16526399219756214973UL, 3305279843951242994UL, 
			6610559687902485989UL, 13221119375804971979UL, 2644223875160994395UL, 
			5288447750321988791UL, 10576895500643977583UL, 2115379100128795516UL, 
			4230758200257591033UL, 8461516400515182066UL, 16923032801030364133UL, 
			3384606560206072826UL, 6769213120412145653UL, 13538426240824291306UL, 
			2707685248164858261UL, 5415370496329716522UL, 10830740992659433045UL, 
			2166148198531886609UL, 4332296397063773218UL, 8664592794127546436UL, 
			17329185588255092872UL, 3465837117651018574UL, 6931674235302037148UL, 
			13863348470604074297UL, 2772669694120814859UL, 5545339388241629719UL, 
			11090678776483259438UL, 2218135755296651887UL, 4436271510593303775UL, 
			8872543021186607550UL, 17745086042373215101UL, 3549017208474643020UL, 
			7098034416949286040UL, 14196068833898572081UL, 2839213766779714416UL, 
			5678427533559428832UL, 11356855067118857664UL, 2271371013423771532UL, 
			4542742026847543065UL, 9085484053695086131UL, 1817096810739017226UL, 
			3634193621478034452UL, 7268387242956068905UL, 14536774485912137810UL, 
			2907354897182427562UL, 5814709794364855124UL, 11629419588729710248UL, 
			2325883917745942049UL, 4651767835491884099UL, 9303535670983768199UL, 
			1860707134196753639UL, 3721414268393507279UL, 7442828536787014559UL, 
			14885657073574029118UL, 2977131414714805823UL, 5954262829429611647UL, 
			11908525658859223294UL, 2381705131771844658UL, 4763410263543689317UL, 
			9526820527087378635UL, 1905364105417475727UL, 3810728210834951454UL, 
			7621456421669902908UL, 15242912843339805817UL, 3048582568667961163UL, 
			6097165137335922326UL, 12194330274671844653UL, 2438866054934368930UL, 
			4877732109868737861UL, 9755464219737475723UL, 1951092843947495144UL, 
			3902185687894990289UL, 7804371375789980578UL, 15608742751579961156UL, 
			3121748550315992231UL, 6243497100631984462UL, 12486994201263968925UL, 
			2497398840252793785UL, 4994797680505587570UL, 9989595361011175140UL, 
			1997919072202235028UL, 3995838144404470056UL, 7991676288808940112UL, 
			15983352577617880224UL, 3196670515523576044UL, 6393341031047152089UL, 
			12786682062094304179UL, 2557336412418860835UL, 5114672824837721671UL, 
			10229345649675443343UL, 2045869129935088668UL, 4091738259870177337UL, 
			8183476519740354675UL, 16366953039480709350UL, 3273390607896141870UL, 
			6546781215792283740UL, 13093562431584567480UL, 2618712486316913496UL, 
			5237424972633826992UL, 10474849945267653984UL, 2094969989053530796UL, 
			4189939978107061593UL, 8379879956214123187UL, 16759759912428246374UL, 
			3351951982485649274UL, 6703903964971298549UL, 13407807929942597099UL, 
			2681561585988519419UL, 5363123171977038839UL, 10726246343954077679UL, 
			2145249268790815535UL, 4290498537581631071UL, 8580997075163262143UL, 
			17161994150326524287UL, 3432398830065304857UL, 6864797660130609714UL, 
			13729595320261219429UL, 2745919064052243885UL, 5491838128104487771UL, 
			10983676256208975543UL, 2196735251241795108UL, 4393470502483590217UL, 
			8786941004967180435UL, 17573882009934360870UL, 3514776401986872174UL, 
			7029552803973744348UL, 14059105607947488696UL, 2811821121589497739UL, 
			5623642243178995478UL, 11247284486357990957UL, 2249456897271598191UL, 
			4498913794543196382UL, 8997827589086392765UL, 17995655178172785531UL, 
			3599131035634557106UL, 7198262071269114212UL, 14396524142538228424UL, 
			2879304828507645684UL, 5758609657015291369UL, 11517219314030582739UL, 
			2303443862806116547UL, 4606887725612233095UL, 9213775451224466191UL, 
			1842755090244893238UL, 3685510180489786476UL, 7371020360979572953UL, 
			14742040721959145907UL, 2948408144391829181UL, 5896816288783658362UL, 
			11793632577567316725UL, 2358726515513463345UL, 4717453031026926690UL, 
			9434906062053853380UL, 1886981212410770676UL, 3773962424821541352UL, 
			7547924849643082704UL, 15095849699286165408UL, 3019169939857233081UL, 
			6038339879714466163UL, 12076679759428932327UL, 2415335951885786465UL, 
			4830671903771572930UL, 9661343807543145861UL, 1932268761508629172UL, 
			3864537523017258344UL, 7729075046034516689UL, 15458150092069033378UL, 
			3091630018413806675UL, 6183260036827613351UL, 12366520073655226703UL, 
			2473304014731045340UL, 4946608029462090681UL, 9893216058924181362UL, 
			1978643211784836272UL, 3957286423569672544UL, 7914572847139345089UL, 
			15829145694278690179UL, 3165829138855738035UL, 6331658277711476071UL, 
			12663316555422952143UL, 2532663311084590428UL, 5065326622169180857UL, 
			10130653244338361715UL, 2026130648867672343UL, 4052261297735344686UL, 
			8104522595470689372UL, 16209045190941378744UL, 3241809038188275748UL, 
			6483618076376551497UL, 12967236152753102995UL, 2593447230550620599UL, 
			5186894461101241198UL, 10373788922202482396UL, 2074757784440496479UL, 
			4149515568880992958UL, 8299031137761985917UL, 16598062275523971834UL, 
			3319612455104794366UL, 6639224910209588733UL, 13278449820419177467UL, 
			2655689964083835493UL, 5311379928167670986UL, 10622759856335341973UL, 
			2124551971267068394UL, 4249103942534136789UL, 8498207885068273579UL, 
			16996415770136547158UL, 3399283154027309431UL, 6798566308054618863UL, 
			13597132616109237726UL, 2719426523221847545UL, 5438853046443695090UL, 
			10877706092887390181UL, 2175541218577478036UL, 4351082437154956072UL, 
			8702164874309912144UL, 17404329748619824289UL, 3480865949723964857UL, 
			6961731899447929715UL, 13923463798895859431UL, 2784692759779171886UL, 
			5569385519558343772UL, 11138771039116687545UL, 2227754207823337509UL, 
			4455508415646675018UL, 8911016831293350036UL, 17822033662586700072UL, 
			3564406732517340014UL, 7128813465034680029UL, 14257626930069360058UL, 
			2851525386013872011UL, 5703050772027744023UL, 11406101544055488046UL, 
			2281220308811097609UL, 4562440617622195218UL, 9124881235244390437UL, 
			1824976247048878087UL, 3649952494097756174UL, 7299904988195512349UL, 
			14599809976391024699UL, 2919961995278204939UL, 5839923990556409879UL, 
			11679847981112819759UL, 2335969596222563951UL, 4671939192445127903UL, 
			9343878384890255807UL, 1868775676978051161UL, 3737551353956102323UL, 
			7475102707912204646UL, 14950205415824409292UL, 2990041083164881858UL, 
			5980082166329763716UL, 11960164332659527433UL, 2392032866531905486UL, 
			4784065733063810973UL, 9568131466127621947UL, 1913626293225524389UL, 
			3827252586451048778UL, 7654505172902097557UL, 15309010345804195115UL, 
			3061802069160839023UL, 6123604138321678046UL, 12247208276643356092UL, 
			2449441655328671218UL, 4898883310657342436UL, 9797766621314684873UL, 
			1959553324262936974UL, 3919106648525873949UL, 7838213297051747899UL, 
			15676426594103495798UL, 3135285318820699159UL, 6270570637641398319UL, 
			12541141275282796638UL, 2508228255056559327UL, 5016456510113118655UL, 
			10032913020226237310UL, 2006582604045247462UL, 4013165208090494924UL, 
			8026330416180989848UL, 16052660832361979697UL, 3210532166472395939UL, 
			6421064332944791878UL, 12842128665889583757UL, 2568425733177916751UL, 
			5136851466355833503UL, 10273702932711667006UL, 2054740586542333401UL, 
			4109481173084666802UL, 8218962346169333605UL, 16437924692338667210UL, 
			3287584938467733442UL, 6575169876935466884UL, 13150339753870933768UL, 
			2630067950774186753UL, 5260135901548373507UL, 10520271803096747014UL, 
			2104054360619349402UL, 4208108721238698805UL, 8416217442477397611UL, 
			16832434884954795223UL, 3366486976990959044UL, 6732973953981918089UL, 
			13465947907963836178UL, 2693189581592767235UL, 5386379163185534471UL, 
			10772758326371068942UL, 2154551665274213788UL, 4309103330548427577UL, 
			8618206661096855154UL, 17236413322193710308UL, 3447282664438742061UL, 
			6894565328877484123UL, 13789130657754968246UL, 2757826131550993649UL, 
			5515652263101987298UL, 11031304526203974597UL, 2206260905240794919UL, 
			4412521810481589838UL, 8825043620963179677UL, 17650087241926359355UL, 
			3530017448385271871UL, 7060034896770543742UL, 14120069793541087484UL, 
			2824013958708217496UL, 5648027917416434993UL, 11296055834832869987UL, 
			2259211166966573997UL, 4518422333933147995UL, 9036844667866295990UL, 
			18073689335732591980UL, 3614737867146518396UL, 7229475734293036792UL, 
			14458951468586073584UL, 2891790293717214716UL, 5783580587434429433UL, 
			11567161174868858867UL, 2313432234973771773UL, 4626864469947543547UL, 
			9253728939895087094UL, 1850745787979017418UL, 3701491575958034837UL, 
			7402983151916069675UL, 14805966303832139350UL, 2961193260766427870UL, 
			5922386521532855740UL, 11844773043065711480UL, 2368954608613142296UL, 
			4737909217226284592UL, 9475818434452569184UL, 1895163686890513836UL, 
			3790327373781027673UL, 7580654747562055347UL, 15161309495124110694UL, 
			3032261899024822138UL, 6064523798049644277UL, 12129047596099288555UL, 
			2425809519219857711UL, 4851619038439715422UL, 9703238076879430844UL, 
			1940647615375886168UL, 3881295230751772337UL, 7762590461503544675UL, 
			15525180923007089351UL, 3105036184601417870UL, 6210072369202835740UL, 
			12420144738405671481UL, 2484028947681134296UL, 4968057895362268592UL, 
			9936115790724537184UL, 1987223158144907436UL, 3974446316289814873UL, 
			7948892632579629747UL, 15897785265159259495UL, 3179557053031851899UL, 
			6359114106063703798UL, 12718228212127407596UL, 2543645642425481519UL, 
			5087291284850963038UL, 10174582569701926077UL, 2034916513940385215UL, 
			4069833027880770430UL, 8139666055761540861UL, 16279332111523081723UL, 
			3255866422304616344UL, 6511732844609232689UL, 13023465689218465379UL, 
			2604693137843693075UL, 5209386275687386151UL, 10418772551374772303UL, 
			2083754510274954460UL, 4167509020549908921UL, 8335018041099817842UL, 
			16670036082199635685UL, 3334007216439927137UL, 6668014432879854274UL, 
			13336028865759708548UL, 2667205773151941709UL, 5334411546303883419UL, 
			10668823092607766838UL, 2133764618521553367UL, 4267529237043106735UL, 
			8535058474086213470UL, 17070116948172426941UL, 3414023389634485388UL, 
			6828046779268970776UL, 13656093558537941553UL, 2731218711707588310UL, 
			5462437423415176621UL, 10924874846830353242UL, 2184974969366070648UL, 
			4369949938732141297UL, 8739899877464282594UL, 17479799754928565188UL, 
			3495959950985713037UL, 6991919901971426075UL, 13983839803942852150UL, 
			2796767960788570430UL, 5593535921577140860UL, 11187071843154281720UL, 
			2237414368630856344UL, 4474828737261712688UL, 8949657474523425376UL, 
			17899314949046850752UL, 3579862989809370150UL, 7159725979618740301UL, 
			14319451959237480602UL, 2863890391847496120UL, 5727780783694992240UL, 
			11455561567389984481UL, 2291112313477996896UL, 4582224626955993792UL, 
			9164449253911987585UL, 1832889850782397517UL, 3665779701564795034UL, 
			7331559403129590068UL, 14663118806259180136UL, 2932623761251836027UL, 
			5865247522503672054UL, 11730495045007344109UL, 2346099009001468821UL, 
			4692198018002937643UL, 9384396036005875287UL, 1876879207201175057UL, 
			3753758414402350114UL, 7507516828804700229UL, 15015033657609400459UL, 
			3003006731521880091UL, 6006013463043760183UL, 12012026926087520367UL, 
			2402405385217504073UL, 4804810770435008147UL, 9609621540870016294UL, 
			1921924308174003258UL, 3843848616348006517UL, 7687697232696013035UL, 
			15375394465392026070UL, 3075078893078405214UL, 6150157786156810428UL, 
			12300315572313620856UL, 2460063114462724171UL, 4920126228925448342UL, 
			9840252457850896685UL, 1968050491570179337UL, 3936100983140358674UL, 
			7872201966280717348UL, 15744403932561434696UL, 3148880786512286939UL, 
			6297761573024573878UL, 12595523146049147757UL, 2519104629209829551UL, 
			5038209258419659102UL, 10076418516839318205UL, 2015283703367863641UL, 
			4030567406735727282UL, 8061134813471454564UL, 16122269626942909129UL, 
			3224453925388581825UL, 6448907850777163651UL, 12897815701554327303UL, 
			2579563140310865460UL, 5159126280621730921UL, 10318252561243461842UL, 
			2063650512248692368UL, 4127301024497384737UL, 8254602048994769474UL, 
			16509204097989538948UL, 3301840819597907789UL, 6603681639195815579UL, 
			13207363278391631158UL, 2641472655678326231UL, 5282945311356652463UL, 
			10565890622713304927UL, 2113178124542660985UL, 4226356249085321970UL, 
			8452712498170643941UL, 16905424996341287883UL, 3381084999268257576UL, 
			6762169998536515153UL, 13524339997073030306UL, 2704867999414606061UL, 
			5409735998829212122UL, 10819471997658424245UL, 2163894399531684849UL, 
			4327788799063369698UL, 8655577598126739396UL, 17311155196253478792UL, 
			3462231039250695758UL, 6924462078501391516UL, 13848924157002783033UL, 
			2769784831400556606UL, 5539569662801113213UL, 11079139325602226427UL, 
			2215827865120445285UL, 4431655730240890570UL, 8863311460481781141UL, 
			17726622920963562283UL, 3545324584192712456UL, 7090649168385424913UL, 
			14181298336770849826UL, 2836259667354169965UL, 5672519334708339930UL, 
			11345038669416679861UL, 2269007733883335972UL, 4538015467766671944UL, 
			9076030935533343889UL, 18152061871066687778UL, 3630412374213337555UL, 
			7260824748426675111UL, 14521649496853350222UL, 2904329899370670044UL, 
			5808659798741340089UL, 11617319597482680178UL, 2323463919496536035UL, 
			4646927838993072071UL, 9293855677986144142UL, 1858771135597228828UL, 
			3717542271194457656UL, 7435084542388915313UL, 14870169084777830627UL, 
			2974033816955566125UL, 5948067633911132251UL, 11896135267822264502UL, 
			2379227053564452900UL, 4758454107128905800UL, 9516908214257811601UL, 
			1903381642851562320UL, 3806763285703124640UL, 7613526571406249281UL, 
			15227053142812498563UL, 3045410628562499712UL, 6090821257124999425UL, 
			12181642514249998850UL, 2436328502849999770UL, 4872657005699999540UL, 
			9745314011399999080UL, 1949062802279999816UL, 3898125604559999632UL, 
			7796251209119999264UL, 15592502418239998528UL, 3118500483647999705UL, 
			6237000967295999411UL, 12474001934591998822UL, 2494800386918399764UL, 
			4989600773836799529UL, 9979201547673599058UL, 1995840309534719811UL, 
			3991680619069439623UL, 7983361238138879246UL, 15966722476277758493UL, 
			3193344495255551698UL, 6386688990511103397UL, 12773377981022206794UL, 
			2554675596204441358UL, 5109351192408882717UL, 10218702384817765435UL, 
			2043740476963553087UL, 4087480953927106174UL, 8174961907854212348UL, 
			16349923815708424697UL, 3269984763141684939UL, 6539969526283369878UL, 
			13079939052566739757UL, 2615987810513347951UL, 5231975621026695903UL, 
			10463951242053391806UL, 2092790248410678361UL, 4185580496821356722UL, 
			8371160993642713444UL, 16742321987285426889UL, 3348464397457085377UL, 
			6696928794914170755UL, 13393857589828341511UL, 2678771517965668302UL, 
			5357543035931336604UL, 10715086071862673209UL, 2143017214372534641UL, 
			4286034428745069283UL, 8572068857490138567UL, 17144137714980277135UL, 
			3428827542996055427UL, 6857655085992110854UL, 13715310171984221708UL, 
			2743062034396844341UL, 5486124068793688683UL, 10972248137587377366UL, 
			2194449627517475473UL, 4388899255034950946UL, 8777798510069901893UL, 
			17555597020139803786UL, 3511119404027960757UL, 7022238808055921514UL, 
			14044477616111843029UL, 2808895523222368605UL, 5617791046444737211UL, 
			11235582092889474423UL, 2247116418577894884UL, 4494232837155789769UL, 
			8988465674311579538UL, 17976931348623159077UL, 3595386269724631815UL, 
			7190772539449263630UL, 14381545078898527261UL, 2876309015779705452UL, 
			5752618031559410904UL, 11505236063118821809UL, 2301047212623764361UL, 
			4602094425247528723UL, 9204188850495057447UL, 1840837770099011489UL, 
			3681675540198022979UL, 7363351080396045958UL);

		private const int32[2048] TensExponentTable = .(
			-323, -323, -322, -322, -322, -322, -321, -321, -321, -320, -320, -320, 
			-319, -319, -319, -319, -318, -318, -318, -317, -317, -317, -316, -316, 
			-316, -316, -315, -315, -315, -314, -314, -314, -313, -313, -313, -313, 
			-312, -312, -312, -311, -311, -311, -310, -310, -310, -310, -309, -309, 
			-309, -308, -308, -308, -307, -307, -307, -307, -306, -306, -306, -305, 
			-305, -305, -304, -304, -304, -304, -303, -303, -303, -302, -302, -302, 
			-301, -301, -301, -301, -300, -300, -300, -299, -299, -299, -298, -298, 
			-298, -298, -297, -297, -297, -296, -296, -296, -295, -295, -295, -295, 
			-294, -294, -294, -293, -293, -293, -292, -292, -292, -291, -291, -291, 
			-291, -290, -290, -290, -289, -289, -289, -288, -288, -288, -288, -287, 
			-287, -287, -286, -286, -286, -285, -285, -285, -285, -284, -284, -284, 
			-283, -283, -283, -282, -282, -282, -282, -281, -281, -281, -280, -280, 
			-280, -279, -279, -279, -279, -278, -278, -278, -277, -277, -277, -276, 
			-276, -276, -276, -275, -275, -275, -274, -274, -274, -273, -273, -273, 
			-273, -272, -272, -272, -271, -271, -271, -270, -270, -270, -270, -269, 
			-269, -269, -268, -268, -268, -267, -267, -267, -267, -266, -266, -266, 
			-265, -265, -265, -264, -264, -264, -263, -263, -263, -263, -262, -262, 
			-262, -261, -261, -261, -260, -260, -260, -260, -259, -259, -259, -258, 
			-258, -258, -257, -257, -257, -257, -256, -256, -256, -255, -255, -255, 
			-254, -254, -254, -254, -253, -253, -253, -252, -252, -252, -251, -251, 
			-251, -251, -250, -250, -250, -249, -249, -249, -248, -248, -248, -248, 
			-247, -247, -247, -246, -246, -246, -245, -245, -245, -245, -244, -244, 
			-244, -243, -243, -243, -242, -242, -242, -242, -241, -241, -241, -240, 
			-240, -240, -239, -239, -239, -239, -238, -238, -238, -237, -237, -237, 
			-236, -236, -236, -235, -235, -235, -235, -234, -234, -234, -233, -233, 
			-233, -232, -232, -232, -232, -231, -231, -231, -230, -230, -230, -229, 
			-229, -229, -229, -228, -228, -228, -227, -227, -227, -226, -226, -226, 
			-226, -225, -225, -225, -224, -224, -224, -223, -223, -223, -223, -222, 
			-222, -222, -221, -221, -221, -220, -220, -220, -220, -219, -219, -219, 
			-218, -218, -218, -217, -217, -217, -217, -216, -216, -216, -215, -215, 
			-215, -214, -214, -214, -214, -213, -213, -213, -212, -212, -212, -211, 
			-211, -211, -211, -210, -210, -210, -209, -209, -209, -208, -208, -208, 
			-208, -207, -207, -207, -206, -206, -206, -205, -205, -205, -204, -204, 
			-204, -204, -203, -203, -203, -202, -202, -202, -201, -201, -201, -201, 
			-200, -200, -200, -199, -199, -199, -198, -198, -198, -198, -197, -197, 
			-197, -196, -196, -196, -195, -195, -195, -195, -194, -194, -194, -193, 
			-193, -193, -192, -192, -192, -192, -191, -191, -191, -190, -190, -190, 
			-189, -189, -189, -189, -188, -188, -188, -187, -187, -187, -186, -186, 
			-186, -186, -185, -185, -185, -184, -184, -184, -183, -183, -183, -183, 
			-182, -182, -182, -181, -181, -181, -180, -180, -180, -180, -179, -179, 
			-179, -178, -178, -178, -177, -177, -177, -176, -176, -176, -176, -175, 
			-175, -175, -174, -174, -174, -173, -173, -173, -173, -172, -172, -172, 
			-171, -171, -171, -170, -170, -170, -170, -169, -169, -169, -168, -168, 
			-168, -167, -167, -167, -167, -166, -166, -166, -165, -165, -165, -164, 
			-164, -164, -164, -163, -163, -163, -162, -162, -162, -161, -161, -161, 
			-161, -160, -160, -160, -159, -159, -159, -158, -158, -158, -158, -157, 
			-157, -157, -156, -156, -156, -155, -155, -155, -155, -154, -154, -154, 
			-153, -153, -153, -152, -152, -152, -152, -151, -151, -151, -150, -150, 
			-150, -149, -149, -149, -149, -148, -148, -148, -147, -147, -147, -146, 
			-146, -146, -145, -145, -145, -145, -144, -144, -144, -143, -143, -143, 
			-142, -142, -142, -142, -141, -141, -141, -140, -140, -140, -139, -139, 
			-139, -139, -138, -138, -138, -137, -137, -137, -136, -136, -136, -136, 
			-135, -135, -135, -134, -134, -134, -133, -133, -133, -133, -132, -132, 
			-132, -131, -131, -131, -130, -130, -130, -130, -129, -129, -129, -128, 
			-128, -128, -127, -127, -127, -127, -126, -126, -126, -125, -125, -125, 
			-124, -124, -124, -124, -123, -123, -123, -122, -122, -122, -121, -121, 
			-121, -121, -120, -120, -120, -119, -119, -119, -118, -118, -118, -117, 
			-117, -117, -117, -116, -116, -116, -115, -115, -115, -114, -114, -114, 
			-114, -113, -113, -113, -112, -112, -112, -111, -111, -111, -111, -110, 
			-110, -110, -109, -109, -109, -108, -108, -108, -108, -107, -107, -107, 
			-106, -106, -106, -105, -105, -105, -105, -104, -104, -104, -103, -103, 
			-103, -102, -102, -102, -102, -101, -101, -101, -100, -100, -100, -99, 
			-99, -99, -99, -98, -98, -98, -97, -97, -97, -96, -96, -96, 
			-96, -95, -95, -95, -94, -94, -94, -93, -93, -93, -93, -92, 
			-92, -92, -91, -91, -91, -90, -90, -90, -89, -89, -89, -89, 
			-88, -88, -88, -87, -87, -87, -86, -86, -86, -86, -85, -85, 
			-85, -84, -84, -84, -83, -83, -83, -83, -82, -82, -82, -81, 
			-81, -81, -80, -80, -80, -80, -79, -79, -79, -78, -78, -78, 
			-77, -77, -77, -77, -76, -76, -76, -75, -75, -75, -74, -74, 
			-74, -74, -73, -73, -73, -72, -72, -72, -71, -71, -71, -71, 
			-70, -70, -70, -69, -69, -69, -68, -68, -68, -68, -67, -67, 
			-67, -66, -66, -66, -65, -65, -65, -65, -64, -64, -64, -63, 
			-63, -63, -62, -62, -62, -62, -61, -61, -61, -60, -60, -60, 
			-59, -59, -59, -58, -58, -58, -58, -57, -57, -57, -56, -56, 
			-56, -55, -55, -55, -55, -54, -54, -54, -53, -53, -53, -52, 
			-52, -52, -52, -51, -51, -51, -50, -50, -50, -49, -49, -49, 
			-49, -48, -48, -48, -47, -47, -47, -46, -46, -46, -46, -45, 
			-45, -45, -44, -44, -44, -43, -43, -43, -43, -42, -42, -42, 
			-41, -41, -41, -40, -40, -40, -40, -39, -39, -39, -38, -38, 
			-38, -37, -37, -37, -37, -36, -36, -36, -35, -35, -35, -34, 
			-34, -34, -34, -33, -33, -33, -32, -32, -32, -31, -31, -31, 
			-30, -30, -30, -30, -29, -29, -29, -28, -28, -28, -27, -27, 
			-27, -27, -26, -26, -26, -25, -25, -25, -24, -24, -24, -24, 
			-23, -23, -23, -22, -22, -22, -21, -21, -21, -21, -20, -20, 
			-20, -19, -19, -19, -18, -18, -18, -18, -17, -17, -17, -16, 
			-16, -16, -15, -15, -15, -15, -14, -14, -14, -13, -13, -13, 
			-12, -12, -12, -12, -11, -11, -11, -10, -10, -10, -9, -9, 
			-9, -9, -8, -8, -8, -7, -7, -7, -6, -6, -6, -6, 
			-5, -5, -5, -4, -4, -4, -3, -3, -3, -3, -2, -2, 
			-2, -1, -1, -1, 0, 0, 0, 1, 1, 1, 1, 2, 
			2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 
			6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 
			9, 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 
			13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 
			16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20, 
			20, 20, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 
			24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 27, 27, 
			27, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 31, 
			31, 31, 32, 32, 32, 32, 33, 33, 33, 34, 34, 34, 
			35, 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 
			38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 41, 
			42, 42, 42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 
			45, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 49, 
			49, 49, 50, 50, 50, 50, 51, 51, 51, 52, 52, 52, 
			53, 53, 53, 53, 54, 54, 54, 55, 55, 55, 56, 56, 
			56, 56, 57, 57, 57, 58, 58, 58, 59, 59, 59, 60, 
			60, 60, 60, 61, 61, 61, 62, 62, 62, 63, 63, 63, 
			63, 64, 64, 64, 65, 65, 65, 66, 66, 66, 66, 67, 
			67, 67, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 
			71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 74, 74, 
			74, 75, 75, 75, 75, 76, 76, 76, 77, 77, 77, 78, 
			78, 78, 78, 79, 79, 79, 80, 80, 80, 81, 81, 81, 
			81, 82, 82, 82, 83, 83, 83, 84, 84, 84, 84, 85, 
			85, 85, 86, 86, 86, 87, 87, 87, 88, 88, 88, 88, 
			89, 89, 89, 90, 90, 90, 91, 91, 91, 91, 92, 92, 
			92, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 96, 
			96, 96, 97, 97, 97, 97, 98, 98, 98, 99, 99, 99, 
			100, 100, 100, 100, 101, 101, 101, 102, 102, 102, 103, 103, 
			103, 103, 104, 104, 104, 105, 105, 105, 106, 106, 106, 106, 
			107, 107, 107, 108, 108, 108, 109, 109, 109, 109, 110, 110, 
			110, 111, 111, 111, 112, 112, 112, 112, 113, 113, 113, 114, 
			114, 114, 115, 115, 115, 116, 116, 116, 116, 117, 117, 117, 
			118, 118, 118, 119, 119, 119, 119, 120, 120, 120, 121, 121, 
			121, 122, 122, 122, 122, 123, 123, 123, 124, 124, 124, 125, 
			125, 125, 125, 126, 126, 126, 127, 127, 127, 128, 128, 128, 
			128, 129, 129, 129, 130, 130, 130, 131, 131, 131, 131, 132, 
			132, 132, 133, 133, 133, 134, 134, 134, 134, 135, 135, 135, 
			136, 136, 136, 137, 137, 137, 137, 138, 138, 138, 139, 139, 
			139, 140, 140, 140, 140, 141, 141, 141, 142, 142, 142, 143, 
			143, 143, 143, 144, 144, 144, 145, 145, 145, 146, 146, 146, 
			147, 147, 147, 147, 148, 148, 148, 149, 149, 149, 150, 150, 
			150, 150, 151, 151, 151, 152, 152, 152, 153, 153, 153, 153, 
			154, 154, 154, 155, 155, 155, 156, 156, 156, 156, 157, 157, 
			157, 158, 158, 158, 159, 159, 159, 159, 160, 160, 160, 161, 
			161, 161, 162, 162, 162, 162, 163, 163, 163, 164, 164, 164, 
			165, 165, 165, 165, 166, 166, 166, 167, 167, 167, 168, 168, 
			168, 168, 169, 169, 169, 170, 170, 170, 171, 171, 171, 171, 
			172, 172, 172, 173, 173, 173, 174, 174, 174, 175, 175, 175, 
			175, 176, 176, 176, 177, 177, 177, 178, 178, 178, 178, 179, 
			179, 179, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 
			183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 186, 186, 
			186, 187, 187, 187, 187, 188, 188, 188, 189, 189, 189, 190, 
			190, 190, 190, 191, 191, 191, 192, 192, 192, 193, 193, 193, 
			193, 194, 194, 194, 195, 195, 195, 196, 196, 196, 196, 197, 
			197, 197, 198, 198, 198, 199, 199, 199, 199, 200, 200, 200, 
			201, 201, 201, 202, 202, 202, 202, 203, 203, 203, 204, 204, 
			204, 205, 205, 205, 206, 206, 206, 206, 207, 207, 207, 208, 
			208, 208, 209, 209, 209, 209, 210, 210, 210, 211, 211, 211, 
			212, 212, 212, 212, 213, 213, 213, 214, 214, 214, 215, 215, 
			215, 215, 216, 216, 216, 217, 217, 217, 218, 218, 218, 218, 
			219, 219, 219, 220, 220, 220, 221, 221, 221, 221, 222, 222, 
			222, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 226, 
			226, 226, 227, 227, 227, 227, 228, 228, 228, 229, 229, 229, 
			230, 230, 230, 230, 231, 231, 231, 232, 232, 232, 233, 233, 
			233, 234, 234, 234, 234, 235, 235, 235, 236, 236, 236, 237, 
			237, 237, 237, 238, 238, 238, 239, 239, 239, 240, 240, 240, 
			240, 241, 241, 241, 242, 242, 242, 243, 243, 243, 243, 244, 
			244, 244, 245, 245, 245, 246, 246, 246, 246, 247, 247, 247, 
			248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 251, 251, 
			251, 252, 252, 252, 252, 253, 253, 253, 254, 254, 254, 255, 
			255, 255, 255, 256, 256, 256, 257, 257, 257, 258, 258, 258, 
			258, 259, 259, 259, 260, 260, 260, 261, 261, 261, 261, 262, 
			262, 262, 263, 263, 263, 264, 264, 264, 265, 265, 265, 265, 
			266, 266, 266, 267, 267, 267, 268, 268, 268, 268, 269, 269, 
			269, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 273, 
			273, 273, 274, 274, 274, 274, 275, 275, 275, 276, 276, 276, 
			277, 277, 277, 277, 278, 278, 278, 279, 279, 279, 280, 280, 
			280, 280, 281, 281, 281, 282, 282, 282, 283, 283, 283, 283, 
			284, 284, 284, 285, 285, 285, 286, 286, 286, 286, 287, 287, 
			287, 288, 288, 288, 289, 289, 289, 289, 290, 290, 290, 291, 
			291, 291, 292, 292, 292, 293, 293, 293 );
		private const char8[16] DigitLowerTable = .('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
		private const char8[16] DigitUpperTable = .('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
		private const int64[19] TenPowersList = .(
			1L,
			10L,
			100L,
			1000L,
			10000L,
			100000L,
			1000000L,
			10000000L,
			100000000L,
			1000000000L,
			10000000000L,
			100000000000L,
			1000000000000L,
			10000000000000L,
			100000000000000L,
			1000000000000000L,
			10000000000000000L,
			100000000000000000L,
			1000000000000000000L);

		// DecHexDigits s a translation table from a decimal number to its
		// digits hexadecimal representation (e.g. DecHexDigits [34] = 0x34).
		private const int32[100] DecHexDigits = .(
			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 
			0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 
			0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 
			0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 
			0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 
			0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 
			0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 
			0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 
			0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 
			0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99);

		static int64 GetTenPowerOf(int i)
		{
			return TenPowersList [i];
		}
		#endregion Static Fields

		#region Fields

		const int BUF_SIZE = 128;

		private NumberFormatInfo _nfi;

		static char8[] sEmtpyBuf = new char8[0] ~ delete _;

		//part of the private stringbuffer
		private char8[] _cbuf ~ if (cbufOnHeap) delete _;
		private bool cbufOnHeap;
		private int32 mBufSize;

		private bool _NaN;
		private bool _infinity;
		private bool _isCustomFormat;
		private bool _specifierIsUpper;
		private bool _positive;
		private char8 _specifier;
		private int32 _precision;
		private int32 _defPrecision;

		private int32 _digitsLen;
		private int32 _offset; // Represent the first digit offset.
		private int32 _decPointPos;

		// The following fields are a hexadeimal representation of the digits.
		// For instance _val = 0x234 represents the digits '2', '3', '4'.
		private uint32 _val1; // Digits 0 - 7.
		private uint32 _val2; // Digits 8 - 15.
		private uint32 _val3; // Digits 16 - 23.
		private uint32 _val4; // Digits 23 - 31. Only needed for decimals.

		#endregion Fields

		#region Constructor Helpers

		// Translate an unsigned int to hexadecimal digits.
		// i.e. 123456789 is represented by _val1 = 0x23456789 and _val2 = 0x1
		private void InitDecHexDigits (uint32 value)
		{
			var value;
			if (value >= HundredMillion)
			{
				int32 div1 = (int32)(value / HundredMillion);
				value -= HundredMillion * (uint32)div1;
				_val2 = FastToDecHex (div1);
			}
			_val1 = ToDecHex ((int32)value);
		}

		// Translate an unsigned long to hexadecimal digits.
		private void InitDecHexDigits (uint64 value)
		{
			var value;
			if (value >= HundredMillion) {
				int64 div1 = (int64)(value / HundredMillion);
				value -= HundredMillion * (uint64)div1;
				if (div1 >= HundredMillion) {
					int32 div2 = (int32)(div1 / HundredMillion);
					div1 = div1 - div2 * (int64)HundredMillion;
					_val3 = ToDecHex (div2);
				}
				if (div1 != 0)
					_val2 = ToDecHex ((int32)(div1));
			}
			if (value != 0)
				_val1 = ToDecHex ((int32)value);
		}

		// Translate a decimal integer to hexadecimal digits.
		// The decimal integer is 96 digits and its value is hi * 2^64 + lo.
		// is the lower 64 bits.
		private void InitDecHexDigits (uint hi, uint64 lo)
		{
			if (hi == 0) {
				InitDecHexDigits (lo); // Only the lower 64 bits matter.
				return;
			}

			var hi;
			var lo;

			// Compute (hi, lo) = (hi , lo) / HundredMillion.
			uint divhi = hi / HundredMillion;
			uint64 remhi = hi - divhi * HundredMillion;
			uint64 divlo = lo / HundredMillion;
			uint64 remlo = lo - divlo * HundredMillion + remhi * ULongModHundredMillion;
			hi = divhi;
			lo = divlo + remhi * ULongDivHundredMillion;
			divlo = remlo / HundredMillion;
			remlo -= divlo * HundredMillion;
			lo += divlo;
			_val1 = ToDecHex ((int32)remlo);

			// Divide hi * 2 ^ 64 + lo by HundredMillion using the fact that
			// hi < HundredMillion.
			divlo = lo / HundredMillion;
			remlo = lo - divlo * HundredMillion;
			lo = divlo;
			if (hi != 0) {
				lo += hi * ULongDivHundredMillion;
				remlo += hi * ULongModHundredMillion;
				divlo = remlo / HundredMillion;
				lo += divlo;
				remlo -= divlo * HundredMillion;
			}
			_val2 = ToDecHex ((int32)remlo);

			// Now we are left with 64 bits store in lo.
			if (lo >= HundredMillion) {
				divlo = lo / HundredMillion;
				lo -= divlo * HundredMillion;
				_val4 = ToDecHex ((int32)divlo);
			}
			_val3 = ToDecHex ((int32)lo);
		}

		// Helper to translate an int in the range 0 .. 9999 to its
		// Hexadecimal digits representation.
		private static uint32 FastToDecHex (int32 val)
		{
			var decHexDigits = DecHexDigits;

			if (val < 100)
				return (uint32)decHexDigits[val];

			// Uses 2^19 (524288) to compute val / 100 for val < 10000.
			int32 v = (val * 5243) >> 19;
			return (uint32)((decHexDigits[v] << 8) | decHexDigits[val - v * 100]);
		}

		// Helper to translate an int in the range 0 .. 99999999 to its
		// Hexadecimal digits representation.
		private static uint32 ToDecHex (int32 val)
		{
			var val;
			uint32 res = 0;
			if (val >= 10000) {
				int32 v = val / 10000;
				val -= v * 10000;
				res = FastToDecHex (v) << 16;
			}
			return res | FastToDecHex (val);
		}

		// Helper to count number of hexadecimal digits in a number.
		private static int32 FastDecHexLen (int32 val)
		{
			if (val < 0x100)
				if (val < 0x10)
					return 1;
				else
					return 2;
			else if (val < 0x1000)
				return 3;
			else
				return 4;
		}

		private static int32 DecHexLen (uint32 val)
		{
			if (val < 0x10000)
				return FastDecHexLen ((int32)val);
			return 4 + FastDecHexLen ((int32)(val >> 16));
		}

		// Count number of hexadecimal digits stored in _val1 .. _val4.
		private int32 DecHexLen ()
		{
			if (_val4 != 0)
				return DecHexLen (_val4) + 24;
			else if (_val3 != 0)
				return DecHexLen (_val3) + 16;
			else if (_val2 != 0)
				return DecHexLen (_val2) + 8;
			else if (_val1 != 0)
				return DecHexLen (_val1);
			else
				return 0;
		}

		// Helper to count the 10th scale (number of digits) in a number
		private static int32 ScaleOrder (int64 hi)
		{
			for (int32 i = TenPowersListLength - 1; i >= 0; i--)
				if (hi >= GetTenPowerOf (i))
					return i + 1;
			return 1;
		}

		// Compute the initial precision for rounding a floating number
		// according to the used format.
		int32 InitialFloatingPrecision ()
		{
			if (_specifier == 'R')
				return _defPrecision + 2;
			if (_precision < _defPrecision)
				return _defPrecision;
			if (_specifier == 'G')
				return Math.Min (_defPrecision + 2, _precision);
			if (_specifier == 'E')
				return Math.Min (_defPrecision + 2, _precision + 1);
			return _defPrecision;
		}

		// Parse the given format and extract the precision in it.
		// Returns -1 for empty formats and -2 to indicate that the format
		// is a custom format.
		private static int32 ParsePrecision (StringView format)
		{
			int32 precision = 0;
			for (int32 i = 1; i < format.Length; i++) {
				int32 val = format [i] - '0';
				precision = precision * 10 + val;
				if (val < 0 || val > 9 || precision > 99)
					return -2;
			}
			return precision;
		}

		#endregion Constructor Helpers

		#region Constructors

		// Parse the given format and initialize the following fields:
		//   _isCustomFormat, _specifierIsUpper, _specifier & _precision.
		this(CultureInfo cultureInfo)
		{
			if (Compiler.IsComptime)
				_cbuf = new char8[0];
			else
				_cbuf = sEmtpyBuf;
			if (cultureInfo != null)
				CurrentCulture = cultureInfo;
		}

		private void Init(StringView format)
		{
			_val1 = _val2 = _val3 = _val4 = 0;
			_offset = 0;
			_NaN = _infinity = false;
			_isCustomFormat = false;
			_specifierIsUpper = true;
			_precision = -1;

			if (format.Ptr == null || format.Length == 0) {
				_specifier = 'G';
				return;
			}

			char8 specifier = format [0];
			if (specifier >= 'a' && specifier <= 'z') {
				specifier = (char8)(specifier - 'a' + 'A');
				_specifierIsUpper = false;
			}
			else if (specifier < 'A' || specifier > 'Z') {
				_isCustomFormat = true;
				_specifier = '0';
				return;
			}
			_specifier = specifier;
			if (format.Length > 1) {
				_precision = ParsePrecision (format);
				if (_precision == -2) { // Is it a custom format?
					_isCustomFormat = true;
					_specifier = '0';
					_precision = -1;
				}
			}
		}

		private void InitHex (uint64 value)
		{
			var value;

			switch (_defPrecision) {
				case Int32DefPrecision: value = (uint32) value;    break;
			}
			_val1 = (uint32)value;
			_val2 = (uint32)(value >> 32);
			_decPointPos = _digitsLen = DecHexLen ();
			if (value == 0)
				_decPointPos = 1;
		}

		private void Init (StringView format, int32 value, int32 defPrecision)
		{
			var value;
			Init (format);
			_defPrecision = defPrecision;
			_positive = value >= 0;

			if (value == 0 || _specifier == 'X' || _specifier == 'A') {
				InitHex ((uint64)value);
				return;
			}

			if (value < 0)
				value = -value;
			InitDecHexDigits ((uint32)value);
			_decPointPos = _digitsLen = DecHexLen ();
		}

		private void Init (StringView format, uint32 value, int32 defPrecision)
		{
			Init (format);
			_defPrecision = defPrecision;
			_positive = true;

			if (value == 0 || _specifier == 'X' || _specifier == 'A') {
				InitHex (value);
				return;
			}

			InitDecHexDigits (value);
			_decPointPos = _digitsLen = DecHexLen ();
		}

		private void Init (StringView format, int64 value)
		{
			var value;
			Init (format);
			_defPrecision = Int64DefPrecision;
			_positive = value >= 0;

			if (value == 0 || _specifier == 'X' || _specifier == 'A') {
				InitHex ((uint64)value);
				return;
			}

			if (value < 0)
				value = -value;
			InitDecHexDigits ((uint64)value);
			_decPointPos = _digitsLen = DecHexLen ();
		}

		private void Init (StringView format, uint64 value)
		{
			Init (format);
			_defPrecision = UInt64DefPrecision;
			_positive = true;

			if (value == 0 || _specifier == 'X' || _specifier == 'A') {
				InitHex ((uint64)value);
				return;
			}

			InitDecHexDigits (value);
			_decPointPos = _digitsLen = DecHexLen ();
		}

		private void Init (StringView format, double value, int32 defPrecision)
		{
			Init (format);

			_defPrecision = defPrecision;
			int64 bits = BitConverter.Convert<double, int64>(value);
		   	_positive = bits >= 0;
			bits &= Int64.MaxValue;
			if (bits == 0) {
				_decPointPos = 1;
				_digitsLen = 0;
				_positive = true;
				return;
			}

			int32 e = (int32)(bits >> DoubleBitsExponentShift);
			int64 m = bits & DoubleBitsMantissaMask;
			if (e == DoubleBitsExponentMask) {
				_NaN = m != 0;
				_infinity = m == 0;
				return;
			}

			int32 expAdjust = 0;
			if (e == 0) {
				// We need 'm' to be large enough so we won't lose precision.
				e = 1;
				int32 scale = ScaleOrder (m);
				if (scale < DoubleDefPrecision) {
					expAdjust = scale - DoubleDefPrecision;
					m *= GetTenPowerOf (-expAdjust);
				}
			}
			else {
				m = (m + DoubleBitsMantissaMask + 1) * 10;
				expAdjust = -1;
			}

			// multiply the mantissa by 10 ^ N
			uint64 lo = (uint32)m;
			uint64 hi = (uint64)m >> 32;
			uint64 lo2 = MantissaBitsTable [e];
			uint64 hi2 = lo2 >> 32;
			lo2 = (uint32)lo2;
			uint64 mm = hi * lo2 + lo * hi2 + ((lo * lo2) >> 32);
			int64 res = (int64)(hi * hi2 + (mm >> 32));
			while (res < SeventeenDigitsThreshold) {
				mm = (mm & UInt32.MaxValue) * 10;
				res = res * 10 + (int64)(mm >> 32);
				expAdjust--;
			}
			if ((mm & 0x80000000) != 0)
				res++;

			int32 order = DoubleDefPrecision + 2;
			_decPointPos = TensExponentTable [e] + expAdjust + order;

			// Rescale 'res' to the initial precision (15-17 for doubles).
			int32 initialPrecision = InitialFloatingPrecision ();
			if (order > initialPrecision) {
				int64 val = GetTenPowerOf (order - initialPrecision);
				res = (res + (val >> 1)) / val;
				order = initialPrecision;
			}
			if (res >= GetTenPowerOf (order)) {
				order++;
				_decPointPos++;
			}

		   	InitDecHexDigits ((uint64)res);
			_offset = CountTrailingZeros ();
			_digitsLen = order - _offset;
		}

		/*private void Init (StringView format, decimal value)
		{
			Init (format);
			_defPrecision = DecimalDefPrecision;

			int[] bits = decimal.GetBits (value);
			int scale = (bits [3] & DecimalBitsScaleMask) >> 16;
			_positive = bits [3] >= 0;
			if (bits [0] == 0 && bits [1] == 0 && bits [2] == 0) {
				_decPointPos = -scale;
				_positive = true;
				_digitsLen = 0;
				return;
			}

		   	InitDecHexDigits ((uint32)bits [2], ((uint64)bits [1] << 32) | (uint32)bits [0]);
			_digitsLen = DecHexLen ();
			_decPointPos = _digitsLen - scale;
			if (_precision != -1 || _specifier != 'G') {
				_offset = CountTrailingZeros ();
				_digitsLen -= _offset;
			}
		}*/

		//_cbuf moved to before other fields to improve layout
		private int _ind;

		private void ResetCharBuf (int size)
		{
			_ind = 0;
			if (_cbuf.Count < size)
			{
				if (cbufOnHeap)
					delete _cbuf;
				_cbuf = new char8 [size];
				cbufOnHeap = true;
			}
		}

		private void Resize (int len)
		{
			char8[] newBuf = new char8[len];
			Array.Copy(_cbuf, 0, newBuf, 0, _cbuf.Count);
			if (cbufOnHeap)
				delete _cbuf;
			_cbuf = newBuf;
			cbufOnHeap = true;
		}

		private void Append (char8 c)
		{
			if (_ind == _cbuf.Count)
				Resize (_ind + 10);
			_cbuf [_ind++] = c;
		}

		private void Append (char8 c, int cnt)
		{
			var cnt;
			if (_ind + cnt > _cbuf.Count)
				Resize (_ind + cnt + 10);
			while (cnt-- > 0)
				_cbuf [_ind++] = c;
		}

		private void Append (StringView s)
		{
			int slen = s.Length;
			if (_ind + slen > _cbuf.Count)
				Resize (_ind + slen + 10);
			for (int i = 0; i < slen; i++)
				_cbuf [_ind++] = s [i];
		}

		#endregion Inner String Buffer

		#region Helper properties

		static NumberFormatInfo sDefaultNFI = new NumberFormatInfo() ~ delete _;

		private NumberFormatInfo GetNumberFormatInstance(IFormatProvider fp)
		{
			if (_nfi != null && fp == null)
				return _nfi;
			return NumberFormatInfo.GetInstance(fp);
		}

		CultureInfo CurrentCulture
		{
			set
			{
				/*if (value != null && value.IsReadOnly)
					_nfi = value.NumberFormat;
				else
					_nfi = null;*/
				//_nfi = value.Nu
				//Runtime.FatalError();
				_nfi = value.mNumInfo;
			}
		}

		private int IntegerDigits {
			get { return _decPointPos > 0 ? _decPointPos : 1; }
		}

		private int DecimalDigits {
			get { return _digitsLen > _decPointPos ? _digitsLen - _decPointPos : 0; }
		}

		private bool IsFloatingSource {
			get { return _defPrecision == DoubleDefPrecision || _defPrecision == SingleDefPrecision; }
		}

		private bool IsZero {
			get { return _digitsLen == 0; }
		}

		private bool IsZeroInteger {
			get { return _digitsLen == 0 || _decPointPos <= 0; }
		}

		#endregion Helper properties

		#region Round

		private void RoundPos (int32 pos)
		{
			RoundBits (_digitsLen - pos);
		}

		private bool RoundDecimal (int32 decimals)
		{
			return RoundBits (_digitsLen - _decPointPos - decimals);
		}

		private bool RoundBits (int32 shift)
		{
			var shift;

			if (shift <= 0)
				return false;

			if (shift > _digitsLen) {
				_digitsLen = 0;
				_decPointPos = 1;
				_val1 = _val2 = _val3 = _val4 = 0;
				_positive = true;
				return false;
			}
			shift += _offset;
			_digitsLen += _offset;
			while (shift > 8) {
				_val1 = _val2;
				_val2 = _val3;
				_val3 = _val4;
				_val4 = 0;
				_digitsLen -= 8;
				shift -= 8;
			}
			shift = (shift - 1) << 2;
			uint32 v = _val1 >> shift;
			uint32 rem16 = v & 0xf;
			_val1 = (v ^ rem16) << shift;
			bool res = false;
			if (rem16 >= 0x5) {
				_val1 |= 0x99999999 >> (int32)(28 - shift);
				AddOneToDecHex ();
				int32 newlen = DecHexLen ();
				res = newlen != _digitsLen;
				_decPointPos = _decPointPos + newlen - _digitsLen;
				_digitsLen = newlen;
			}
			RemoveTrailingZeros ();
			return res;
		}

		private void RemoveTrailingZeros ()
		{
			_offset = CountTrailingZeros ();
			_digitsLen -= _offset;
			if (_digitsLen == 0) {
				_offset = 0;
				_decPointPos = 1;
				_positive = true;
			}
		}

		private void AddOneToDecHex ()
		{
			if (_val1 == 0x99999999) {
				_val1 = 0;
				if (_val2 == 0x99999999) {
					_val2 = 0;
					if (_val3 == 0x99999999) {
						_val3 = 0;
						_val4 = AddOneToDecHex (_val4);
					}
					else
						_val3 = AddOneToDecHex (_val3);
				}
				else
					_val2 = AddOneToDecHex (_val2);
			}
			else
				_val1 = AddOneToDecHex (_val1);
		}

		// Assume val != 0x99999999
		private static uint32 AddOneToDecHex (uint32 val)
		{
			if ((val & 0xffff) == 0x9999)
				if ((val & 0xffffff) == 0x999999)
					if ((val & 0x0fffffff) == 0x09999999)
						return val + 0x06666667;
					else
						return val + 0x00666667;
				else if ((val & 0xfffff) == 0x99999)
					return val + 0x00066667;
				else
					return val + 0x00006667;
			else if ((val & 0xff) == 0x99)
				if ((val & 0xfff) == 0x999)
					return val + 0x00000667;
				else
					return val + 0x00000067;
			else if ((val & 0xf) == 0x9)
				return val + 0x00000007;
			else
				return val + 1;
		}

		private int32 CountTrailingZeros ()
		{
			if (_val1 != 0)
				return CountTrailingZeros (_val1);
			if (_val2 != 0)
				return CountTrailingZeros (_val2) + 8;
			if (_val3 != 0)
				return CountTrailingZeros (_val3) + 16;
			if (_val4 != 0)
				return CountTrailingZeros (_val4) + 24;
			return _digitsLen;
		}

		private static int32 CountTrailingZeros (uint val)
		{
			if ((val & 0xffff) == 0)
				if ((val & 0xffffff) == 0)
					if ((val & 0x0fffffff) == 0)
						return 7;
					else
						return 6;
				else if ((val & 0xfffff) == 0)
					return 5;
				else
					return 4;
			else if ((val & 0xff) == 0)
				if ((val & 0xfff) == 0)
					return 3;
				else
					return 2;
			else if ((val & 0xf) == 0)
				return 1;
			else
				return 0;
		}

		#endregion Round

		#region public number formatting methods

		static LazyTLS<NumberFormatter> threadNumberFormatter = new .(
			new () => new NumberFormatter(CultureInfo.CurrentCulture),
			new (nf) => { delete nf; }) ~ delete _;

		static LazyTLS<NumberFormatter> userNumberFormatter = new .(
			new () => new NumberFormatter(null),
			new (nf) => { delete nf; }) ~ delete _;

		[ThreadStatic]
		static NumberFormatter userFormatProvider;

		private static NumberFormatter GetInstance(IFormatProvider fp)
		{
			if (fp != null)
			{
				return userNumberFormatter.Value;
			}
			else
			{
				var nf = threadNumberFormatter.Value;
				nf.CurrentCulture = CultureInfo.CurrentCulture;
				return nf;
			}
		}

		public static void NumberToString (StringView format, uint32 value, IFormatProvider fp, String outString)
		{
			NumberFormatter inst = GetInstance(fp);
			inst.Init (format, value, UInt32DefPrecision);
			inst.IntegerToString(format, fp, outString);
		}

		public static void AddrToString (uint value, String outString)
		{
			const int bufLen = 18;
			char8* strChars = scope:: char8[bufLen]* (?);	
			int32 curLen = 0;	
			uint64 valLeft = (.)value;
			while (valLeft > 0)	
			{	
				if (curLen == 8)	
					strChars[bufLen - curLen++ - 1] = '\'';	
			    strChars[bufLen - curLen++ - 1] = DigitUpperTable[(int)(valLeft & 0xF)];
			    valLeft >>= 4;	
			}	

			while (curLen < 10)	
			{	
				if (curLen == 8)	
					strChars[bufLen - curLen++ - 1] = '\'';	
				strChars[bufLen - curLen++ - 1] = '0';	
			}	

			char8* char8Ptr = &strChars[bufLen - curLen];	
			outString.Append(char8Ptr, curLen);
		}

		public static void NumberToString (StringView format, int32 value, IFormatProvider fp, String outString)
		{
			NumberFormatter inst = GetInstance(fp);
			inst.Init (format, value, Int32DefPrecision);
			inst.IntegerToString (format, fp, outString);
		}

		public static void NumberToString (StringView format, uint64 value, IFormatProvider fp, String outString)
		{
			NumberFormatter inst = GetInstance(fp);
			inst.Init (format, value);
			inst.IntegerToString (format, fp, outString);
		}

		public static void NumberToString (StringView format, int64 value, IFormatProvider fp, String outString)
		{
			NumberFormatter inst = GetInstance(fp);
			inst.Init (format, value);
			inst.IntegerToString (format, fp, outString);
		}

		public static void NumberToString (StringView format, float value, IFormatProvider fp, String outString)
		{
			NumberFormatter inst = GetInstance(fp);
			inst.Init (format, value, SingleDefPrecision);
			NumberFormatInfo nfi = inst.GetNumberFormatInstance(fp);
			if (inst._NaN)
				outString.Append(nfi.NaNSymbol);
			else if (inst._infinity)
				if (inst._positive)
					outString.Append(nfi.PositiveInfinitySymbol);
				else
					outString.Append(nfi.NegativeInfinitySymbol);
			else if (inst._specifier == 'R')
				inst.FormatRoundtrip (value, nfi, outString);
			else
				inst.NumberToString (format, nfi, outString);
		}

		public static void NumberToString (StringView format, double value, IFormatProvider fp, String outString)
		{
			NumberFormatter inst = GetInstance(fp);
			inst.Init (format, value, DoubleDefPrecision);
			NumberFormatInfo nfi = inst.GetNumberFormatInstance(fp);
			if (inst._NaN)
				outString.Append(nfi.NaNSymbol);
			else if (inst._infinity)
				if (inst._positive)
					outString.Append(nfi.PositiveInfinitySymbol);
				else
					outString.Append(nfi.NegativeInfinitySymbol);
			else if (inst._specifier == 'R')
				inst.FormatRoundtrip (value, nfi, outString);
			else
				inst.NumberToString (format, nfi, outString);
		}

		/*public static void NumberToString (string format, decimal value, IFormatProvider fp, String outString)
		{
			NumberFormatter inst = GetInstance(fp);
			inst.Init (format, value);
			string res = inst.NumberToString (format, inst.GetNumberFormatInstance (fp));
			inst.Release();
			return res;
		}*/

		private void IntegerToString (StringView format, IFormatProvider fp, String outString)
		{
			NumberFormatInfo nfi = GetNumberFormatInstance (fp);
			switch (_specifier)
			{
			case 'A':
				FormatAddress(outString);
			case 'C':
				FormatCurrency (_precision, nfi, outString);
			case 'D':
				FormatDecimal (_precision, nfi, outString);
			case 'E':
				FormatExponential (_precision, nfi, outString);
			case 'F':
				FormatFixedPoint (_precision, nfi, outString);
			case 'G':
				if (_precision <= 0)
					FormatDecimal (-1, nfi, outString);
				FormatGeneral (_precision, nfi, outString);
			case 'N':
				FormatNumber (_precision, nfi, outString);
			case 'P':
				FormatPercent (_precision, nfi, outString);
			case 'X':
				FormatHexadecimal (_precision, outString);
			default:
				if (_isCustomFormat)
				{
					FormatCustom (format, nfi, outString);
					return;
				}
				//throw new FormatException ("The specified format '" + format + "' is invalid");
				Runtime.FatalError("The specified format is invalid");
			}
		}

		private void NumberToString (StringView format, NumberFormatInfo nfi, String outString)
		{
			switch (_specifier) {
			case 'C':
				FormatCurrency (_precision, nfi, outString);
			case 'E':
				FormatExponential (_precision, nfi, outString);
			case 'F':
				FormatFixedPoint (_precision, nfi, outString);
			case 'G':
				FormatGeneral (_precision, nfi, outString);
			case 'N':
				FormatNumber (_precision, nfi, outString);
			case 'P':
				FormatPercent (_precision, nfi, outString);
			case 'X':
			default:
				if (_isCustomFormat)
				{
					FormatCustom (format, nfi, outString);
					return;
				}
				//throw new FormatException ("The specified format '" + format + "' is invalid");
				Runtime.FatalError("The specified format is invalid");
			}
		}

		void FormatCurrency (int32 precision, NumberFormatInfo nfi, String outString)
		{
			var precision;

			precision = (precision >= 0 ? precision : nfi.CurrencyDecimalDigits);
			RoundDecimal (precision);
			ResetCharBuf (IntegerDigits * 2 + precision * 2 + 16);

			if (_positive) {
				switch (nfi.CurrencyPositivePattern) {
				case 0:
					Append (nfi.CurrencySymbol);
					break;
				case 2:
					Append (nfi.CurrencySymbol);
					Append (' ');
					break;
				}
			}
			else {
				switch (nfi.CurrencyNegativePattern) {
				case 0:
					Append ('(');
					Append (nfi.CurrencySymbol);
					break;
				case 1:
					Append (nfi.NegativeSign);
					Append (nfi.CurrencySymbol);
					break;
				case 2:
					Append (nfi.CurrencySymbol);
					Append (nfi.NegativeSign);
					break;
				case 3:
					Append (nfi.CurrencySymbol);
					break;
				case 4:
					Append ('(');
					break;
				case 5:
					Append (nfi.NegativeSign);
					break;
				case 8:
					Append (nfi.NegativeSign);
					break;
				case 9:
					Append (nfi.NegativeSign);
					Append (nfi.CurrencySymbol);
					Append (' ');
					break;
				case 11:
					Append (nfi.CurrencySymbol);
					Append (' ');
					break;
				case 12:
					Append (nfi.CurrencySymbol);
					Append (' ');
					Append (nfi.NegativeSign);
					break;
				case 14:
					Append ('(');
					Append (nfi.CurrencySymbol);
					Append (' ');
					break;
				case 15:
					Append ('(');
					break;
				}
			}

			AppendIntegerStringWithGroupSeparator (nfi.CurrencyGroupSizes, nfi.CurrencyGroupSeparator);

			if (precision > 0) {
				Append (nfi.CurrencyDecimalSeparator);
				AppendDecimalString (precision);
			}

			if (_positive) {
				switch (nfi.CurrencyPositivePattern) {
				case 1:
					Append (nfi.CurrencySymbol);
					break;
				case 3:
					Append (' ');
					Append (nfi.CurrencySymbol);
					break;
				}
			}
			else {
				switch (nfi.CurrencyNegativePattern) {
				case 0:
					Append (')');
					break;
				case 3:
					Append (nfi.NegativeSign);
					break;
				case 4:
					Append (nfi.CurrencySymbol);
					Append (')');
					break;
				case 5:
					Append (nfi.CurrencySymbol);
					break;
				case 6:
					Append (nfi.NegativeSign);
					Append (nfi.CurrencySymbol);
					break;
				case 7:
					Append (nfi.CurrencySymbol);
					Append (nfi.NegativeSign);
					break;
				case 8:
					Append (' ');
					Append (nfi.CurrencySymbol);
					break;
				case 10:
					Append (' ');
					Append (nfi.CurrencySymbol);
					Append (nfi.NegativeSign);
					break;
				case 11:
					Append (nfi.NegativeSign);
					break;
				case 13:
					Append (nfi.NegativeSign);
					Append (' ');
					Append (nfi.CurrencySymbol);
					break;
				case 14:
					Append (')');
					break;
				case 15:
					Append (' ');
					Append (nfi.CurrencySymbol);
					Append (')');
					break;
				}
			}

			outString.Append(_cbuf, 0, _ind);
		}

		private void FormatDecimal (int32 precision, NumberFormatInfo nfi, String outString)
		{
			var precision;
			if (precision < _digitsLen)
				precision = _digitsLen;
			if (precision == 0)
			{
				outString.Append("0");
				return;
			}

			ResetCharBuf (precision + 1);
			if (!_positive)
				Append (nfi.NegativeSign);
			AppendDigits (0, precision);

			outString.Append(_cbuf, 0, _ind);
		}

		private void FormatHexadecimal (int32 precision, String outString)
		{
			int32 size = Math.Max (precision, _decPointPos);
			
			ResetCharBuf (size);
			_ind = size;
			uint64 val = _val1 | ((uint64)_val2 << 32);
			while (size > 0) {
				_cbuf [--size] = _specifierIsUpper ? DigitUpperTable[val & 0xf] : DigitLowerTable[val & 0xf];
				val >>= 4;
			}
			outString.Append(_cbuf, 0, _ind);
		}

		private void FormatAddress(String outString)
		{
			const int bufLen = 18;
			char8* strChars = scope:: char8[bufLen]* (?);	
			int32 curLen = 0;	
			uint64 valLeft = _val1 | ((uint64)_val2 << 32);
			while (valLeft > 0)	
			{	
				if (curLen == 8)	
					strChars[bufLen - curLen++ - 1] = '\'';	
			    strChars[bufLen - curLen++ - 1] = _specifierIsUpper ? DigitUpperTable[(int)(valLeft & 0xF)] : DigitLowerTable[(int)(valLeft & 0xF)];
			    valLeft >>= 4;	
			}	

			while (curLen < 10)	
			{	
				if (curLen == 8)	
					strChars[bufLen - curLen++ - 1] = '\'';	
				strChars[bufLen - curLen++ - 1] = '0';	
			}	

			char8* char8Ptr = &strChars[bufLen - curLen];	
			outString.Append(char8Ptr, curLen);
		}

		void FormatFixedPoint (int32 precision, NumberFormatInfo nfi, String outString)
		{
			var precision;

			if (precision == -1)
				precision = nfi.NumberDecimalDigits;

			RoundDecimal (precision);

			ResetCharBuf (IntegerDigits + precision + 2);

			if (!_positive)
				Append (nfi.NegativeSign);

			AppendIntegerString (IntegerDigits);

			if (precision > 0) {
				Append (nfi.NumberDecimalSeparator);
				AppendDecimalString (precision);
			}

			outString.Append(_cbuf, 0, _ind);
		}

		private void FormatRoundtrip (double origval, NumberFormatInfo nfi, String outString)
		{
			/*NumberFormatter nfc = GetClone ();
			if (origval >= MinRoundtripVal && origval <= MaxRoundtripVal) {
				string shortRep = FormatGeneral (_defPrecision, nfi);
				if (origval == Double.Parse (shortRep, nfi))
					return shortRep;
			}
			return nfc.FormatGeneral (_defPrecision + 2, nfi);*/

			FormatGeneral (_defPrecision + 2, nfi, outString);
		}

		private void FormatRoundtrip (float origval, NumberFormatInfo nfi, String outString)
		{
			/*NumberFormatter nfc = GetClone ();
			FormatGeneral (_defPrecision, nfi);
			// Check roundtrip only for "normal" double values.
			if (origval == Float.Parse(shortRep, nfi))
				return shortRep;
			return nfc.FormatGeneral (_defPrecision + 2, nfi);*/
			FormatGeneral (_defPrecision + 2, nfi, outString);
		}

		private void FormatGeneral (int32 precision, NumberFormatInfo nfi, String outString)
		{
			var precision;
			bool enableExp;
			if (precision == -1) {
				enableExp = IsFloatingSource;
				precision = _defPrecision;
			}
			else {
				enableExp = true;
				if (precision == 0)
					precision = _defPrecision;
				RoundPos (precision);
			}

			int32 intDigits = _decPointPos;
			int32 digits = _digitsLen;
			int32 decDigits = digits - intDigits;

			if ((intDigits > precision || intDigits <= -4) && enableExp)
			{
				FormatExponential (digits - 1, nfi, 2, outString);
				return;
			}

			if (decDigits < 0)
				decDigits = 0;
			if (intDigits < 0)
				intDigits = 0;
			ResetCharBuf (decDigits + intDigits + 3);

			if (!_positive)
				Append (nfi.NegativeSign);

			if (intDigits == 0)
				Append ('0');
			else
				AppendDigits (digits - intDigits, digits);

			if (decDigits > 0) {
				Append (nfi.NumberDecimalSeparator);
				AppendDigits (0, decDigits);
			}

			outString.Append(_cbuf, 0, _ind);
		}

		void FormatNumber (int32 precision, NumberFormatInfo nfi, String outString)
		{
			var precision;
			precision = (precision >= 0 ? precision : nfi.NumberDecimalDigits);
			ResetCharBuf (IntegerDigits * 3 + precision);
			RoundDecimal (precision);

			if (!_positive) {
				switch (nfi.NumberNegativePattern) {
				case 0:
					Append ('(');
					break;
				case 1:
					Append (nfi.NegativeSign);
					break;
				case 2:
					Append (nfi.NegativeSign);
					Append (' ');
					break;
				}
			}

			AppendIntegerStringWithGroupSeparator (nfi.NumberGroupSizes, nfi.NumberGroupSeparator);

			if (precision > 0) {
				Append (nfi.NumberDecimalSeparator);
				AppendDecimalString (precision);
			}

			if (!_positive) {
				switch (nfi.NumberNegativePattern) {
				case 0:
					Append (')');
					break;
				case 3:
					Append (nfi.NegativeSign);
					break;
				case 4:
					Append (' ');
					Append (nfi.NegativeSign);
					break;
				}
			}

			outString.Append(_cbuf, 0, _ind);
		}

		void FormatPercent (int32 precision, NumberFormatInfo nfi, String outString)
		{
			var precision;
			precision = (precision >= 0 ? precision : nfi.PercentDecimalDigits);
			Multiply10(2);
			RoundDecimal (precision);
			ResetCharBuf (IntegerDigits * 2 + precision + 16);

			if (_positive) {
				if (nfi.PercentPositivePattern == 2)
					Append (nfi.PercentSymbol);
			}
			else {
				switch (nfi.PercentNegativePattern) {
				case 0:
					Append (nfi.NegativeSign);
					break;
				case 1:
					Append (nfi.NegativeSign);
					break;
				case 2:
					Append (nfi.NegativeSign);
					Append (nfi.PercentSymbol);
					break;
				}
			}

			AppendIntegerStringWithGroupSeparator (nfi.PercentGroupSizes, nfi.PercentGroupSeparator);

			if (precision > 0) {
				Append (nfi.PercentDecimalSeparator);
				AppendDecimalString (precision);
			}

			if (_positive) {
				switch (nfi.PercentPositivePattern) {
				case 0:
					Append (' ');
					Append (nfi.PercentSymbol);
					break;
				case 1:
					Append (nfi.PercentSymbol);
					break;
				}
			}
			else {
				switch (nfi.PercentNegativePattern) {
				case 0:
					Append (' ');
					Append (nfi.PercentSymbol);
					break;
				case 1:
					Append (nfi.PercentSymbol);
					break;
				}
			}

			outString.Append(_cbuf, 0, _ind);
		}

		void FormatExponential (int32 precision, NumberFormatInfo nfi, String outString)
		{
			var precision;

			if (precision == -1)
				precision = DefaultExpPrecision;

			RoundPos (precision + 1);
			FormatExponential (precision, nfi, 3, outString);
		}

		private void FormatExponential (int32 precision, NumberFormatInfo nfi, int32 expDigits, String outString)
		{
			int32 decDigits = _decPointPos;
			int32 digits = _digitsLen;
			int32 exponent = decDigits - 1;
			decDigits = _decPointPos = 1;

			ResetCharBuf (precision + 8);

			if (!_positive)
				Append (nfi.NegativeSign);

			AppendOneDigit (digits - 1);

			if (precision > 0) {
				Append (nfi.NumberDecimalSeparator);
				AppendDigits (digits - precision - 1, digits - _decPointPos);
			}

			AppendExponent (nfi, exponent, expDigits);

			outString.Append(_cbuf, 0, _ind);
		}

		void FormatCustom (StringView format, NumberFormatInfo nfi, String outString)
		{
			bool p = _positive;
			int32 offset = 0;
			int32 length = 0;
			CustomInfo.GetActiveSection (format, ref p, IsZero, ref offset, ref length);
			if (length == 0)
			{
				outString.Append(_positive ? String.Empty : nfi.NegativeSign);
				return;
			}
			_positive = p;

			CustomInfo info = scope .();
			CustomInfo.Parse (info, format, offset, length, nfi);
#if false
			Console.WriteLine ("Format : {0}",format);
			Console.WriteLine ("DecimalDigits : {0}",info.DecimalDigits);
			Console.WriteLine ("DecimalPointPos : {0}",info.DecimalPointPos);
			Console.WriteLine ("DecimalTailSharpDigits : {0}",info.DecimalTailSharpDigits);
			Console.WriteLine ("IntegerDigits : {0}",info.IntegerDigits);
			Console.WriteLine ("IntegerHeadSharpDigits : {0}",info.IntegerHeadSharpDigits);
			Console.WriteLine ("IntegerHeadPos : {0}",info.IntegerHeadPos);
			Console.WriteLine ("UseExponent : {0}",info.UseExponent);
			Console.WriteLine ("ExponentDigits : {0}",info.ExponentDigits);
			Console.WriteLine ("ExponentTailSharpDigits : {0}",info.ExponentTailSharpDigits);
			Console.WriteLine ("ExponentNegativeSignOnly : {0}",info.ExponentNegativeSignOnly);
			Console.WriteLine ("DividePlaces : {0}",info.DividePlaces);
			Console.WriteLine ("Percents : {0}",info.Percents);
			Console.WriteLine ("Permilles : {0}",info.Permilles);
#endif
			String sb_int = scope String (info.IntegerDigits * 2);
			String sb_dec = scope String (info.DecimalDigits * 2);
			String sb_exp = (info.UseExponent ? scope:: String(info.ExponentDigits * 2) : null);

			int diff = 0;
			if (info.Percents > 0)
				Multiply10(2 * info.Percents);
			if (info.Permilles > 0)
				Multiply10(3 * info.Permilles);
			if (info.DividePlaces > 0)
				Divide10(info.DividePlaces);

			bool expPositive = true;
			if (info.UseExponent && (info.DecimalDigits > 0 || info.IntegerDigits > 0)) {
				if (!IsZero) {
					RoundPos (info.DecimalDigits + info.IntegerDigits);
					diff -= _decPointPos - info.IntegerDigits;
					_decPointPos = info.IntegerDigits;
				}

				expPositive = diff <= 0;
				AppendNonNegativeNumber (sb_exp, diff < 0 ? -diff : diff);
			}
			else
				RoundDecimal (info.DecimalDigits);

			if (info.IntegerDigits != 0 || !IsZeroInteger)
				AppendIntegerString (IntegerDigits, sb_int);

			AppendDecimalString (DecimalDigits, sb_dec);

			if (info.UseExponent) {
				if (info.DecimalDigits <= 0 && info.IntegerDigits <= 0)
					_positive = true;

				if (sb_int.Length < info.IntegerDigits)
					sb_int.Insert (0, '0', info.IntegerDigits - sb_int.Length);

				while (sb_exp.Length < info.ExponentDigits - info.ExponentTailSharpDigits)
					sb_exp.Insert (0, '0');

				if (expPositive && !info.ExponentNegativeSignOnly)
					sb_exp.Insert (0, nfi.PositiveSign);
				else if (!expPositive)
					sb_exp.Insert (0, nfi.NegativeSign);
			}
			else {
				if (sb_int.Length < info.IntegerDigits - info.IntegerHeadSharpDigits)
					sb_int.Insert (0, '0', info.IntegerDigits - info.IntegerHeadSharpDigits - sb_int.Length);
				if (info.IntegerDigits == info.IntegerHeadSharpDigits && IsZeroOnly (sb_int))
					sb_int.Remove (0, sb_int.Length);
			}

			ZeroTrimEnd (sb_dec, true);
			while (sb_dec.Length < info.DecimalDigits - info.DecimalTailSharpDigits)
				sb_dec.Append ('0');
			if (sb_dec.Length > info.DecimalDigits)
				sb_dec.Remove (info.DecimalDigits, sb_dec.Length - info.DecimalDigits);

			info.Format (format, offset, length, nfi, _positive, sb_int, sb_dec, sb_exp, outString);
		}
		#endregion public number formatting methods

		#region StringBuilder formatting helpers

		private static void ZeroTrimEnd (String sb, bool canEmpty)
		{
			int len = 0;
			for (int i = sb.Length - 1; (canEmpty ? i >= 0 : i > 0); i--) {
				if (sb [i] != '0')
					break;
				len++;
			}

			if (len > 0)
				sb.Remove (sb.Length - len, len);
		}

		private static bool IsZeroOnly (String sb)
		{
			for (int i = 0; i < sb.Length; i++)
				if ((sb [i]).IsDigit && sb [i] != '0')
					return false;
			return true;
		}

		private static void AppendNonNegativeNumber (String sb, int v)
		{
			var v;
			if (v < 0)
				//throw new ArgumentException ();
				Runtime.FatalError();

			int i = ScaleOrder (v) - 1;
			repeat
			{
				int n = v / (int32)GetTenPowerOf (i);
				sb.Append ((char8)('0' + n));
				v -= (int32)GetTenPowerOf (i--) * n;
			}
			while (i >= 0);
		}

		#endregion StringBuilder formatting helpers

		#region Append helpers

		private void AppendIntegerString (int minLength, String sb)
		{
			if (_decPointPos <= 0) {
				sb.Append ('0', minLength);
				return;
			}

			if (_decPointPos < minLength)
				sb.Append ('0', minLength - _decPointPos);

			AppendDigits (_digitsLen - _decPointPos, _digitsLen, sb);
		}

		private void AppendIntegerString (int minLength)
		{
			if (_decPointPos <= 0) {
				Append ('0', minLength);
				return;
			}

			if (_decPointPos < minLength)
				Append ('0', minLength - _decPointPos);

			AppendDigits (_digitsLen - _decPointPos, _digitsLen);
		}

		private void AppendDecimalString (int precision, String sb)
		{
			AppendDigits (_digitsLen - precision - _decPointPos, _digitsLen - _decPointPos, sb);
		}

		private void AppendDecimalString (int precision)
		{
			AppendDigits (_digitsLen - precision - _decPointPos, _digitsLen - _decPointPos);
		}

		private void AppendIntegerStringWithGroupSeparator (Span<int32> groups, StringView groupSeparator)
		{
			if (IsZeroInteger) {
				Append ('0');
				return;
			}

			int total = 0;
			int groupIndex = 0;
			for (int i = 0; i < groups.Length; i++) {
				total += groups [i];
				if (total <= _decPointPos)
					groupIndex = i;
				else
					break;
			}

			if (groups.Length > 0 && total > 0) {
				int counter;
				int groupSize = groups [groupIndex];
				int fraction = _decPointPos > total ? _decPointPos - total : 0;
				if (groupSize == 0) {
					while (groupIndex >= 0 && groups [groupIndex] == 0)
						groupIndex--;

					groupSize = fraction > 0 ? fraction : groups [groupIndex];
				}
				if (fraction == 0)
					counter = groupSize;
				else {
					groupIndex += fraction / groupSize;
					counter = fraction % groupSize;
					if (counter == 0)
						counter = groupSize;
					else
						groupIndex++;
				}

				if (total >= _decPointPos) {
					int lastGroupSize = groups [0];
					if (total > lastGroupSize) {
						int lastGroupDiff = -(lastGroupSize - _decPointPos);
						int lastGroupMod;

						if (lastGroupDiff < lastGroupSize)
							counter = lastGroupDiff;
						else if (lastGroupSize > 0 && (lastGroupMod = _decPointPos % lastGroupSize) > 0)
							counter = lastGroupMod;
					}
				}
				
				for (int i = 0; ;) {
					if ((_decPointPos - i) <= counter || counter == 0) {
						AppendDigits (_digitsLen - _decPointPos, _digitsLen - i);
						break;
					}
					AppendDigits (_digitsLen - i - counter, _digitsLen - i);
					i += counter;
					Append (groupSeparator);
					if (--groupIndex < groups.Length && groupIndex >= 0)
						groupSize = groups [groupIndex];
					counter = groupSize;
				}
			}
			else {
				AppendDigits (_digitsLen - _decPointPos, _digitsLen);
			}
		}

		// minDigits is in the range 1..3
		private void AppendExponent (NumberFormatInfo nfi, int32 exponent, int32 minDigits)
		{
			var exponent;

			if (_specifierIsUpper || _specifier == 'R')
				Append ('E');
			else
				Append ('e');

			if (exponent >= 0)
				Append (nfi.PositiveSign);
			else {
				Append (nfi.NegativeSign);
				exponent = -exponent;
			}

			if (exponent == 0)
				Append ('0', minDigits);
			else if (exponent < 10) {
				Append ('0', minDigits - 1);
				Append ((char8)('0' | (char8)exponent));
			}
			else {
				uint hexDigit = FastToDecHex(exponent);
				if (exponent >= 100 || minDigits == 3)
					Append ((char8)('0' | (char8)(hexDigit >> 8)));
				Append ((char8)('0' | (char8)((hexDigit >> 4) & 0xf)));
				Append ((char8)('0' | (char8)(hexDigit & 0xf)));
			}
		}

		private void AppendOneDigit (int32 start)
		{
			var start;
			if (_ind == _cbuf.Count)
				Resize (_ind + 10);

			start += _offset;
			uint v;
			if (start < 0)
				v = 0;
			else if (start < 8)
				v = _val1;
			else if (start < 16)
				v = _val2;
			else if (start < 24)
				v = _val3;
			else if (start < 32)
				v = _val4;
			else
				v = 0;
			v >>= (start & 0x7) << 2;
			_cbuf [_ind++] = (char8)('0' | (char8)(v & 0xf));
		}

		private void AppendDigits (int start, int end)
		{
			if (start >= end)
				return;

			var end;
			var start;

			int i = _ind + (end - start);
			if (i > _cbuf.Count)
				Resize (i + 10);
			_ind = i;

			end += _offset;
			start += _offset;

			for (int next = start + 8 - (start & 0x7); ; start = next, next += 8) {
				uint v;
				if (next == 8)
					v = _val1;
				else if (next == 16)
					v = _val2;
				else if (next == 24)
					v = _val3;
				else if (next == 32)
					v = _val4;
				else
					v = 0;
				v >>= (start & 0x7) << 2;
				if (next > end)
					next = end;

				_cbuf [--i] = (char8)('0' | (char8)(v & 0xf));
				switch (next - start) {
				case 8:
					_cbuf [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 7:
					_cbuf [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 6:
					_cbuf [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 5:
					_cbuf [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 4:
					_cbuf [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 3:
					_cbuf [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 2:
					_cbuf [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 1:
					if (next == end)
						return;
					continue;
				}
			}
		}

		private void AppendDigits (int start, int end, String sb)
		{
			if (start >= end)
				return;

			int i = sb.Length + (end - start);
			sb.PrepareBuffer(i);

			var end;
			var start;

			end += _offset;
			start += _offset;

			for (int next = start + 8 - (start & 0x7); ; start = next, next += 8) {
				uint v;
				if (next == 8)
					v = _val1;
				else if (next == 16)
					v = _val2;
				else if (next == 24)
					v = _val3;
				else if (next == 32)
					v = _val4;
				else
					v = 0;
				v >>= (start & 0x7) << 2;
				if (next > end)
					next = end;
				sb [--i] = (char8)('0' | (char8)(v & 0xf));
				switch (next - start) {
				case 8:
					sb [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 7:
					sb [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 6:
					sb [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 5:
					sb [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 4:
					sb [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 3:
					sb [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 2:
					sb [--i] = (char8)('0' | (char8)((v >>= 4) & 0xf));
					fallthrough;
				case 1:
					if (next == end)
						return;
					continue;
				}
			}
		}

		#endregion Append helpers

		#region others

		private void Multiply10(int32 count)
		{
			if (count <= 0 || _digitsLen == 0)
				return;

			_decPointPos += count;
		}

		private void Divide10(int32 count)
		{
			if (count <= 0 || _digitsLen == 0)
				return;

			_decPointPos -= count;
		}

		/*private NumberFormatter GetClone ()
		{
			return (NumberFormatter)this.MemberwiseClone ();
		}*/

		#endregion others

		#region custom

		private class CustomInfo
		{
			public bool UseGroup = false;
			public int32 DecimalDigits = 0;
			public int32 DecimalPointPos = -1;
			public int32 DecimalTailSharpDigits = 0;
			public int32 IntegerDigits = 0;
			public int32 IntegerHeadSharpDigits = 0;
			public int32 IntegerHeadPos = 0;
			public bool UseExponent = false;
			public int32 ExponentDigits = 0;
			public int32 ExponentTailSharpDigits = 0;
			public bool ExponentNegativeSignOnly = true;
			public int32 DividePlaces = 0;
			public int32 Percents = 0;
			public int32 Permilles = 0;

			public static void GetActiveSection (StringView format, ref bool positive, bool zero, ref int32 offset, ref int32 length)
			{
				int32[3] lens = .(0,);
				int32 index = 0;
				int32 lastPos = 0;
				bool quoted = false;

				for (int32 i = 0; i < format.Length; i++) {
					char8 c = format [i];

					if (c == '\"' || c == '\'') {
						if (i == 0 || format [i - 1] != '\\')
							quoted = !quoted;

						continue;
					}

					if (c == ';' && !quoted && (i == 0 || format [i - 1] != '\\')) {
						lens [index++] = i - lastPos;
						lastPos = i + 1;
						if (index == 3)
							break;
					}
				}

				if (index == 0) {
					offset = 0;
					length = (.)format.Length;
					return;
				}
				if (index == 1) {
					if (positive || zero) {
						offset = 0;
						length = lens [0];
						return;
					}
					if (lens [0] + 1 < format.Length) {
						positive = true;
						offset = lens [0] + 1;
						length = (.)format.Length - offset;
						return;
					}
					else {
						offset = 0;
						length = lens [0];
						return;
					}
				}
				if (zero) {
					if (index == 2) {
						if (format.Length - lastPos == 0) {
							offset = 0;
							length = lens [0];
						} else {
							offset = lens [0] + lens [1] + 2;
							length = (.)format.Length - offset;
						}
						return;
					}

					if (lens [2] == 0) {
						offset = 0;
						length = lens [0];
					} else {
						offset = lens [0] + lens [1] + 2;
						length = lens [2];
					}

					return;

				}
				if (positive) {
					offset = 0;
					length = lens [0];
					return;
				}
				if (lens [1] > 0) {
					positive = true;
					offset = lens [0] + 1;
					length = lens [1];
					return;
				}
				offset = 0;
				length = lens [0];
			}

			public static void Parse (CustomInfo info, StringView format, int32 offset, int32 length, NumberFormatInfo nfi)
			{
				char8 literal = '\0';
				bool integerArea = true;
				bool decimalArea = false;
				bool exponentArea = false;
				bool sharpContinues = true;

				int32 groupSeparatorCounter = 0;

				for (int i = offset; i - offset < length; i++)
				{
					char8 c = format [i];

					if (c == literal && c != '\0') {
						literal = '\0';
						continue;
					}
					if (literal != '\0')
						continue;

					if (exponentArea && (c != '\0' && c != '0' && c != '#')) {
						exponentArea = false;
						integerArea = (info.DecimalPointPos < 0);
						decimalArea = !integerArea;
						i--;
						continue;
					}

					switch (c) {
					case '\\':
						i++;
						continue;
					case '\'':
					case '\"':
						if (c == '\"' || c == '\'') {
							literal = c;
						}
						continue;
					case '#':
						if (sharpContinues && integerArea)
							info.IntegerHeadSharpDigits++;
						else if (decimalArea)
							info.DecimalTailSharpDigits++;
						else if (exponentArea)
							info.ExponentTailSharpDigits++;

						fallthrough;
					case '0':
						if (c != '#') {
							sharpContinues = false;
							if (decimalArea)
								info.DecimalTailSharpDigits = 0;
							else if (exponentArea)
								info.ExponentTailSharpDigits = 0;
						}
						if (info.IntegerHeadPos == -1)
							info.IntegerHeadPos = (.)i;

						if (integerArea) {
							info.IntegerDigits++;
							if (groupSeparatorCounter > 0)
								info.UseGroup = true;
							groupSeparatorCounter = 0;
						}
						else if (decimalArea)
							info.DecimalDigits++;
						else if (exponentArea)
							info.ExponentDigits++;
						break;
					case 'e':
					case 'E':
						if (info.UseExponent)
							break;

						info.UseExponent = true;
						integerArea = false;
						decimalArea = false;
						exponentArea = true;
						if (i + 1 - offset < length) {
							char8 nc = format [i + 1];
							if (nc == '+')
								info.ExponentNegativeSignOnly = false;
							if (nc == '+' || nc == '-')
								i++;
							else if (nc != '0' && nc != '#') {
								info.UseExponent = false;
								if (info.DecimalPointPos < 0)
									integerArea = true;
							}
						}

						break;
					case '.':
						integerArea = false;
						decimalArea = true;
						exponentArea = false;
						if (info.DecimalPointPos == -1)
							info.DecimalPointPos = (.)i;
						break;
					case '%':
						info.Percents++;
						break;
					case ',':
						if (integerArea && info.IntegerDigits > 0)
							groupSeparatorCounter++;
						break;
					default:
						if (c >= '\x80')
						{
							let (c32, len) = format.GetChar32(i);
							if (c32 == '\u{2030}')
							{
								info.Permilles++;
								i += len - 1;
								break;
							}
						}
						break;
					}
				}

				if (info.ExponentDigits == 0)
					info.UseExponent = false;
				else
					info.IntegerHeadSharpDigits = 0;

				if (info.DecimalDigits == 0)
					info.DecimalPointPos = -1;

				info.DividePlaces += groupSeparatorCounter * 3;
			}

			public void Format (StringView format, int offset, int length, NumberFormatInfo nfi, bool positive, String sb_int, String sb_dec, String sb_exp, String sb)
			{
				var sb_exp;

				int startPos = sb.Length;

				//String sb = scope String();
				char8 literal = '\0';
				bool integerArea = true;
				bool decimalArea = false;
				int intSharpCounter = 0;
				int sb_int_index = 0;
				int sb_dec_index = 0;

				Span<int32> groups = nfi.NumberGroupSizes;
				StringView groupSeparator = nfi.NumberGroupSeparator;
				int intLen = 0, total = 0, groupIndex = 0, counter = 0, groupSize = 0;
				if (UseGroup && groups.Length > 0) {
					intLen = sb_int.Length;
					for (int i = 0; i < groups.Length; i++) {
						total += groups [i];
						if (total <= intLen)
							groupIndex = i;
					}
					groupSize = groups [groupIndex];
					int fraction = intLen > total ? intLen - total : 0;
					if (groupSize == 0) {
						while (groupIndex >= 0 && groups [groupIndex] == 0)
							groupIndex--;

						groupSize = fraction > 0 ? fraction : groups [groupIndex];
					}
					if (fraction == 0)
						counter = groupSize;
					else {
						groupIndex += fraction / groupSize;
						counter = fraction % groupSize;
						if (counter == 0)
							counter = groupSize;
						else
							groupIndex++;
					}
				}
				else
					UseGroup = false;

				for (int i = offset; i - offset < length; i++)
				{
					char8 c = format [i];

					if (c == literal && c != '\0') {
						literal = '\0';
						continue;
					}
					if (literal != '\0') {
						sb.Append (c);
						continue;
					}

					switch (c) {
					case '\\':
						i++;
						if (i - offset < length)
							sb.Append (format [i]);
						continue;
					case '\'':
					case '\"':
						if (c == '\"' || c == '\'')
							literal = c;
						continue;
					case '#':
						fallthrough;
					case '0':
						if (integerArea) {
							intSharpCounter++;
							if (IntegerDigits - intSharpCounter < sb_int.Length + sb_int_index || c == '0')
								while (IntegerDigits - intSharpCounter + sb_int_index < sb_int.Length) {
									sb.Append (sb_int [sb_int_index++]);
									if (UseGroup && --intLen > 0 && --counter == 0) {
										sb.Append (groupSeparator);
										if (--groupIndex < groups.Length && groupIndex >= 0)
											groupSize = groups [groupIndex];
										counter = groupSize;
									}
								}
							break;
						}
						else if (decimalArea) {
							if (sb_dec_index < sb_dec.Length)
								sb.Append (sb_dec [sb_dec_index++]);
							break;
						}

						sb.Append (c);
						break;
					case 'e':
					case 'E':
						if (sb_exp == null || !UseExponent) {
							sb.Append (c);
							break;
						}

						bool flag1 = true;
						bool flag2 = false;

						int q;
						for (q = i + 1; q - offset < length; q++) {
							if (format [q] == '0') {
								flag2 = true;
								continue;
							}
							if (q == i + 1 && (format [q] == '+' || format [q] == '-'))
								continue;
							if (!flag2)
								flag1 = false;
							break;
						}

						if (flag1) {
							i = q - 1;
							integerArea = (DecimalPointPos < 0);
							decimalArea = !integerArea;

							sb.Append (c);
							sb.Append (sb_exp);
							sb_exp = null;
						}
						else
							sb.Append (c);

						break;
					case '.':
						if (DecimalPointPos == i) {
							if (DecimalDigits > 0) {
								while (sb_int_index < sb_int.Length)
									sb.Append (sb_int [sb_int_index++]);
							}
							if (sb_dec.Length > 0)
								sb.Append (nfi.NumberDecimalSeparator);
						}
						integerArea = false;
						decimalArea = true;
						break;
					case ',':
						break;
					case '%':
						sb.Append (nfi.PercentSymbol);
						break;
					default:
						if (c >= '\x80')
						{
							let (c32, len) = format.GetChar32(i);
							if (c32 == '\u{2030}')
							{
								sb.Append (nfi.PerMilleSymbol);
								i += len - 1;
								break;
							}
						}

						sb.Append (c);
						break;
					}
				}

				if (!positive)
					sb.Insert(startPos, nfi.NegativeSign);

				//return sb.ToString ();
			}
		}

		#endregion
	}
}

